2012-02-15 52 views
1

我有一个维护一个列表的对象;的辅助方法一个需要断言当前线程没有保存一个CRITICAL_SECTION锁

  • 锁定列表
  • 找到的第一个元素
  • 解锁名单
  • 通知另一个线程来开始清除操作
  • 等待另一个线程来完成
  • 重复此操作,直到列表为空。

清理操作从另一个线程的列表中删除对象,因此它需要锁定其中的列表。

这工作正常,只要帮助器没有调用列表上的锁已被占用,然后解锁操作实际上不会允许其他线程访问列表,所以我想标记错误这个案例。

据我所知,CRITICAL_SECTION API没有提供官方支持的方式来查询当前进程是否持有这个对象,所以我正在考虑“hack-ish”方法(毕竟,这是一个调试援助和不打算进入生产代码):

变1是检查CRITICAL_SECTION结构的OwningThread领域,但我不知道是否有保证,这个领域是

  • 总是包含一个线程来自与GetCurrentThreadId()结果相同的编号空间的ID
  • 当任何线程需要锁
  • 总是被清零时,我自己的线程释放锁总是更新

变2是锁定CRITICAL_SECTION然后检查RecursionCount;这假定递归计数器具有固定的起始值。

有没有什么我错过了,我可以用它来构建一个有点面向未来的(也就是说,它会在一行代码中喧闹地接近我解释的全部注释)assertion statement目前的线程是不是的持有者是一定的CRITICAL_SECTION

+0

你不能依赖于任何一个关键部分结构,因为它们是实现依赖,且执行近来已经改变的领域。 – 2012-02-15 09:30:24

+0

因此[tag:hack]标签。 – 2012-02-15 09:34:12

+0

你的设计听起来很不错。您正在尝试检测调用线程是否已锁定?如果你不知道锁定任何给定的代码段,那么你几乎没有机会编写正确和无死锁的代码。 – 2012-02-15 09:59:49

回答

2

让您自己的关键部分提供这样的功能。在你的调试版本中使用它。在发布版本中,使用常规关键部分。

一个简单的方法是使用两个关键部分和一个所有者字段。收购这样的作品:

  1. 获取第一关键部分。

  2. 获取第二关键部分。

  3. 将拥有者设置为该主题。

  4. 发布第二个关键部分。

版本是这样的:

  1. 采集第二个关键部分。

  2. 将所有者设置为无。

  3. 发布第一个关键部分。

  4. 发布第二个关键部分。

断言是这样的:

  1. 采集第二个关键部分。

  2. 断言所有者不是这个线程。

  3. 发布第二个关键部分。

更新:有在上面的错误。它错误地处理了这种情况:锁定,锁定,解锁,断言我们没有保留关键部分,但是我们这样做。该修复可能会保持“锁计数”。您不必将锁定计数设置为“无主”。如果锁定计数为零,则它是无主的。所以assert路径“无主或者不是这个线程”。

+0

其实你不需要第二个关键部分。您可以使用原始的关键部分来保护自己。 – 2012-02-15 14:29:04

+0

@RaymondChen如果你有一个原子操作来检查所有者,你可以。否则,您必须获得主要关键部分才能断言,否则您必须依靠文字撕裂而不是所有者价值的问题。 (在某些情况下,这不是问题,也许在大多数情况下。) – 2012-02-15 14:48:34

+1

是的,它假定“当前所有者”字段已正确对齐。但由于'CRITICAL_SECTION'必须已经对齐,所以只需将“当前所有者”放在'CRITICAL_SECTION'旁边即可轻松实现。 – 2012-02-15 15:07:09

1

我用类似的东西

class CriticalSection 
{ 
private: 
    CRITICAL_SECTION section_; 
    unsigned int owning_thread_id_; 
    unsigned int lock_count_; 

public: 
    CriticalSection() 
    { 
    InitializeCriticalSection(&section_); 
    owning_thread_id_ = 0; 
    lock_count_ = 0; 

    } 
    ~CriticalSection() 
    { 
    DeleteCriticalSection(&section_); 
    } 

    void enter() 
    { 
    EnterCriticalSection(&section_); 
    owning_thread_id_ = GetCurrentThreadId(); 
    lock_count_ ++; 
    } 
    void leave() 
    { 

    if( GetCurrentThreadId() == owning_thread_id_) 
    { 
     lock_count_ --; 
     if(lock_count_ == 0) 
     owning_thread_id_ = 0; 
    } 

    LeaveCriticalSection(&section_); 
    } 

    bool tryEnter() 
    { 
    if(TryEnterCriticalSection(&section_)) 
    { 
     owning_thread_id_ = GetCurrentThreadId(); 
     lock_count_ ++; 
     return true; 
    } 
    return false; 
    } 

    bool isCurrentThreadEntered() 
    { 
    return GetCurrentThreadId() == owning_thread_id_; 
    } 

    int getLockCount() { return lock_count_; } 
    unsigned int getOwningThreadID() { return owning_thread_id_; } 

};