断言当前线程没有持有 CRITICAL_SECTION 锁

发布于 2025-01-05 06:45:45 字数 800 浏览 1 评论 0原文

我有一个维护列表的对象;其中一个辅助方法需要

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

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

只要在已经持有列表上的锁的情况下不调用助手,这种方法就可以正常工作,因为解锁操作实际上不会允许其他线程访问列表,所以我想在这种情况下标记一个错误。

据我所知,CRITICAL_SECTION API 没有提供官方支持的方法来查询当前进程是否持有此对象,因此我正在考虑“hack-ish”方法(毕竟,它是一种调试辅助工具,并不打算进入生产代码):

变体 1 是检查 CRITICAL_SECTION 结构的 OwningThread 字段,但我想知道是否可以保证这个领域 始终包含

  • 来自与 GetCurrentThreadId() 相同数字空间的线程 ID
  • 当任何线程获取锁时结果总是更新
  • 当我自己的线程释放锁时总是

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

有没有我错过的东西可以用来构建一个有点面向未来的(也就是说,它会在靠近我解释这一切的注释的代码行中大声中断)当前线程的断言语句不是某个CRITICAL_SECTION的持有者?

I have an object that maintains a list; one of the helper methods needs to

  • lock the list
  • find the first element
  • unlock the list
  • notify another thread to start a cleanup operation
  • wait on the other thread to finish
  • repeat this until the list is empty.

The cleanup operation removes the object from the list from the other thread, thus it needs to lock the list in between.

This works fine as long as the helper is not called with the lock on the list already held as then the unlock operation will not actually allow the other thread to access the list, so I'd like to flag an error in this case.

As far as I've understood, the CRITICAL_SECTION API does not provide an officially supported way to query whether the current process holds this object, so I'm considering "hack-ish" approaches (after all, it's a debugging aid and not intended to go into production code):

Variant 1 is to check the OwningThread field of the CRITICAL_SECTION structure, but I wonder whether there is a guarantee that this field is

  • always containing a thread ID from the same number space as GetCurrentThreadId() results
  • always updated when any thread takes the lock
  • always cleared when my own thread releases the lock

Variant 2 is to lock the CRITICAL_SECTION and then examine the RecursionCount; this assumes that the recursion counter has a fixed start value.

Is there anything that I have missed that I could use to build a somewhat future-proof (that is, it will break noisily in a line of code that is near to the comments where I explain it all) assertion statement that the current thread is not the holder of a certain CRITICAL_SECTION?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萌酱 2025-01-12 06:45:46

创建您自己的提供此类功能的关键部分。在调试版本中使用它。在发布版本中,使用常规关键部分。

一种简单的方法是使用两个关键部分和一个所有者字段。获取的工作方式如下:

  1. 获取第一个关键部分。

  2. 获取第二个关键部分。

  3. 设置该线程的所有者。

  4. 释放第二个关键部分。

发布的工作方式如下:

  1. 获取第二个关键部分。

  2. 将所有者设置为无。

  3. 释放第一个关键部分。

  4. 释放第二个关键部分。

断言的工作方式如下:

  1. 获取第二个关键部分。

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

  3. 释放第二个关键部分。

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

Make your own critical section that provides such a feature. Use it in your debug builds. In release builds, use the regular critical section.

One simple way is to use two critical sections and an owner field. Acquire works like this:

  1. Acquire first critical section.

  2. Acquire second critical section.

  3. Set owner to this thread.

  4. Release second critical section.

Release works like this:

  1. Acquire second critical section.

  2. Set owner to none.

  3. Release first critical section.

  4. Release second critical section.

Assert works like this:

  1. Acquire second critical section.

  2. Assert owner is not this thread.

  3. Release second critical section.

Update: There's a bug in the above. It mishandles this case: lock, lock, unlock, assert that we don't hold the critical section but we do. The fix is probably to keep a "lock count". You don't have to set the CS to "unowned" with the lock count. If the lock count is zero, it's unowned. So the assert paths "unowned or owner not this thread".

甜点 2025-01-12 06:45:46

我用类似的东西

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

public:
  CriticalSection() 
  {
    InitializeCriticalSection(§ion_);
    owning_thread_id_ = 0;
    lock_count_ = 0;

  }
  ~CriticalSection()
  {
    DeleteCriticalSection(§ion_);
  }

  void enter()
  {
    EnterCriticalSection(§ion_);
    owning_thread_id_ = GetCurrentThreadId();
    lock_count_ ++;
  }
  void leave()
  {

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

    LeaveCriticalSection(§ion_);
  }

  bool tryEnter() 
  { 
    if( TryEnterCriticalSection(§ion_))
    {
      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_; }

};

I use something like that

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

public:
  CriticalSection() 
  {
    InitializeCriticalSection(§ion_);
    owning_thread_id_ = 0;
    lock_count_ = 0;

  }
  ~CriticalSection()
  {
    DeleteCriticalSection(§ion_);
  }

  void enter()
  {
    EnterCriticalSection(§ion_);
    owning_thread_id_ = GetCurrentThreadId();
    lock_count_ ++;
  }
  void leave()
  {

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

    LeaveCriticalSection(§ion_);
  }

  bool tryEnter() 
  { 
    if( TryEnterCriticalSection(§ion_))
    {
      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_; }

};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文