65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIconemptyStarIcon

1.55/5 (9投票s)

2005年2月23日

2分钟阅读

viewsIcon

26080

downloadIcon

284

命名临界区和命名自旋锁——您可能会发现它对于调试复杂应用程序很有用。

引言

处理临界区并非易事。当然,如果您只有两个线程和一个临界区,那还可以。但是,如果您有大约 10 个线程,并且需要同步大约 20-30 个变量的使用,那么您可能会遇到问题。一个非常有用的工具是 Sysinternals 的 ProcessExplorer。但它并没有告诉您太多关于临界区对象的信息。因此,我需要一种方法来跟踪所有临界区,它们何时被锁定/解锁,以及由谁锁定。

使用代码

要使用这些类,您必须具备关于 CCriticalSectionCSingleLock 的基础知识。如果没有,请在从 MSDN 阅读完所有相关内容后再回来。这对于 /DEBUG 模式和 /RELEASE 模式都有效。但只有在 /DEBUG 模式下,您才能跟踪所有临界区的“活动”。在 /RELEASE 模式下,您将不会收到任何调试消息。不过,如果您希望看到它们,则可以编辑 debugtrace.cppdebugtrace.h 文件,并删除所有 #ifndef#endif 行。

首先,将 debugtrace.hdebugtrace.cppspinlock.hspinlock.cppnamedcriticalsection.hnamedcriticalsection.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 是一件非常困难的事情。嗯,它并不难,实际上相当简单。只需记住 CNamedCriticalSectionCSpinLock 的构造函数需要一个名称字符串。

关注点

这很有趣 :)。说实话,在编写包含大量线程的大型应用程序时,您会需要这个。

历史

  • 版本 1.0 - 2005 年 2 月 23 日 - 如 CDebugTrace 文章中所承诺的,我也发布了这个。
© . All rights reserved.