【问题标题】:Is it valid to nest a critical section?嵌套临界区是否有效?
【发布时间】:2011-08-31 16:41:34
【问题描述】:

例如,这是否有效?

CRITICAL_SECTION cs;

::InitializeCriticalSection( &cs );

::EnterCriticalSection( &cs );      // First level
::EnterCriticalSection( &cs );        // Second level

/* do some stuff */

::LeaveCriticalSection( &cs );        // Second level
::LeaveCriticalSection( &cs );      // First level

::DeleteCriticalSection( &cs );

显然,我绝不会故意这样做,但如果这是由于函数调用导致调用“第一级”以锁定对象以用于复杂(例如搜索)算法和“第二级”在该对象的访问器函数中被调用?

【问题讨论】:

    标签: c++ winapi critical-section


    【解决方案1】:

    是的,进入相同的临界区是有效的。来自the docs

    线程拥有临界区所有权后,它可以使 对 EnterCriticalSection 或 TryEnterCriticalSection 的额外调用 在不阻止其执行的情况下。这可以防止线程 在等待它的关键部分时死锁自己 已经拥有。线程每次进入临界区 EnterCriticalSection 和 TryEnterCriticalSection 成功。一根线 每次进入时必须调用 LeaveCriticalSection 临界区。

    【讨论】:

    • 这同样适用于所有其他类型的同步对象——互斥体、信号量等。一旦一个线程获得了锁,它可以在不阻塞的情况下多次重新进入锁。只需确保释放锁的次数与您输入锁的次数相同,以便正确释放以供其他线程获取。
    • @Remy:不,它不适用于所有其他类型的同步对象。你当然可以有不可重入的互斥体。
    • 标准互斥体是可重入的。来自 MSDN 的引述:“拥有互斥锁的线程可以在重复的等待函数调用中指定相同的互斥锁,而不会阻塞其执行。通常,您不会重复等待同一个互斥锁,但是这种机制可以防止线程在等待时死锁自己它已经拥有的互斥锁。但是,要释放其所有权,线程必须在互斥锁每次满足等待时调用一次 ReleaseMutex。"
    • @Remy:它确实适用于信号量,你不能随心所欲地获取信号量。来自 MSDN 的引述:“但是,重复等待同一个信号量对象的线程会在每次等待操作完成时递减信号量的计数;当计数变为零时,线程会被阻塞。”
    【解决方案2】:

    来自documentation

    线程拥有临界区的所有权后,它可以对 EnterCriticalSection 或 TryEnterCriticalSection 进行额外调用,而不会阻塞其执行。这可以防止线程在等待它已经拥有的临界区时自行死锁。每次 EnterCriticalSection 和 TryEnterCriticalSection 成功时线程进入临界区。线程每次进入临界区时都必须调用一次 LeaveCriticalSection。

    【讨论】:

    • 是的,但是......好吧,我称之为平局。
    • 谢谢! - 现在投票很便宜。顺便说一句,我赞成马蒂尼奥赢得比赛。 ps:我打算只写“是”作为我的答案,但认为引用来源会很有趣。
    【解决方案3】:

    验证其他两个帖子。快速查看 WinDbg 中的关键部分可以看出,关键部分维护一个整数变量来保存递归计数。

    0:001> dt RTL_CRITICAL_SECTION
    +0x000 DebugInfo : Ptr32 _RTL_CRITICAL_SECTION_DEBUG
    +0x004 LockCount : Int4B
    +0x008 RecursionCount : Int4B
    +0x00c OwningThread : Ptr32 Void
    +0x010 LockSemaphore : Ptr32 Void
    +0x014 SpinCount : Uint4B 
    

    递归计数 - 线程可以多次获取临界区。这个领域 表示同一个线程获取临界区的次数。经过 默认情况下,该字段的值为0,表示没有线程拥有 临界区。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-01-25
      • 1970-01-01
      • 2011-08-02
      • 2023-01-03
      • 2015-01-12
      • 2018-10-17
      • 2013-03-26
      相关资源
      最近更新 更多