Hardwired 的命名临界区和命名自旋锁






1.55/5 (9投票s)
2005年2月23日
2分钟阅读

26080

284
命名临界区和命名自旋锁——您可能会发现它对于调试复杂应用程序很有用。
引言
处理临界区并非易事。当然,如果您只有两个线程和一个临界区,那还可以。但是,如果您有大约 10 个线程,并且需要同步大约 20-30 个变量的使用,那么您可能会遇到问题。一个非常有用的工具是 Sysinternals 的 ProcessExplorer。但它并没有告诉您太多关于临界区对象的信息。因此,我需要一种方法来跟踪所有临界区,它们何时被锁定/解锁,以及由谁锁定。
使用代码
要使用这些类,您必须具备关于 CCriticalSection
和 CSingleLock
的基础知识。如果没有,请在从 MSDN 阅读完所有相关内容后再回来。这对于 /DEBUG 模式和 /RELEASE 模式都有效。但只有在 /DEBUG 模式下,您才能跟踪所有临界区的“活动”。在 /RELEASE 模式下,您将不会收到任何调试消息。不过,如果您希望看到它们,则可以编辑 debugtrace.cpp 和 debugtrace.h 文件,并删除所有 #ifndef
和 #endif
行。
首先,将 debugtrace.h、debugtrace.cpp、spinlock.h、spinlock.cpp、namedcriticalsection.h 和 namedcriticalsection.cpp 文件添加到您的项目中,并在需要的地方添加 #include "namedcriticalsection.h"
。
使用 CNamedCriticalSection
非常简单,只需按照以下步骤操作:
// // MyClass.h // #include "namedcriticalsection.h" class MyClass { CNamedCriticalSection Section; public: MyClass(); ~MyClass(); void SomeMethod(void); ... };
// // MyClass.cpp // #include "myclass.h" MyClass::MyClass() : Section( "MyClass" ) // the critical section object should have // the same name as the class, but you can // set it to whatever you want { ... } MyClass::~MyClass() { ... } // // let's assume this gets executed only by one single thread // void MyClass::SomeMethod(void) { CSpinLock Spin( &Section, "MyClass::SomeMethod" ); if( Spin.Lock() ) { // // locked section; this is where you operate with // protected data // ... Spin.Unlock(); } }
好的。因此,该类有一个成员函数,用于锁定该部分并获得对某些数据进行操作的独占权限。我们还假设 MyClass::SomeFunction()
仅由一个线程执行,比如说进程的主线程。
假设应用程序启动了另一个线程,该线程想要使用与 MyClass::SomeFunction()
锁定的数据相同的数据。这意味着我们必须等待临界区被解锁。一旦被主线程解锁,新线程就会锁定它。请同时阅读下面代码示例中的注释。
// // Thread function - started with AfxThreadBegin(...), for example // UINT SomeThread( LPVOID lParam ) { MyClass *pmy = NULL; if( NULL == ( pmy = (MyClass*)lParam ) ) return 0; // // create the spinlock // we'll use different name for spin, so we'll know that the section // is locked by the thread function // CSpinLock Spin( &(pmy->Section), "SomeThread" ); // // try to lock the section // this actualy waits infinitely till the other thread unlocks the section // if( Spin.Lock() ) { // // locked section; this is where you operate with // protected data // ... // // finished, so let's unlock the section because the other // thread waits for it. If not, you'll probably get a deadlock!!! // Spin.Unlock(); } ... return 1; }
就是这样!非常简单(我认为 :)),但我相信您会觉得它很有用。它帮助我找到了很多 bug。
还有一点:如果您的应用程序已经有很多源代码,您可能会认为将 CCriticalSection
替换为 CNamedCriticalSection
,将 CSingleLock
替换为 CSpinLocK
是一件非常困难的事情。嗯,它并不难,实际上相当简单。只需记住 CNamedCriticalSection
和 CSpinLock
的构造函数需要一个名称字符串。
关注点
这很有趣 :)。说实话,在编写包含大量线程的大型应用程序时,您会需要这个。
历史
- 版本 1.0 - 2005 年 2 月 23 日 - 如 CDebugTrace 文章中所承诺的,我也发布了这个。