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

C++ 中的“同步”语句(类似 Java)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.10/5 (22投票s)

2005年12月18日

2分钟阅读

viewsIcon

141837

设计和实现一个类似于 Java 中 “synchronized” 语句的 C++ 语句。

引言

本文展示了如何在 C++ 中编写一个 `synchronized` 语句,使其工作方式类似于 Java。该代码的目标是使如下代码片段在 C++ 中可编译和执行:

synchronized(myMutex)
{
    //TODO put synchronized code here
}

Mutex 类

以下代码片段展示了一个具有 lock/unlock 语义的 mutex 类(许多库中常见):

//mutex class
class Mutex
{
public:
    //the default constructor
    Mutex()
    {
        InitializeCriticalSection(&m_criticalSection);
    }

    //destructor
    ~Mutex()
    {
        DeleteCriticalSection(&m_criticalSection);
    }

    //lock
    void lock()
    {
        EnterCriticalSection(&m_criticalSection);
    }

    //unlock
    void unlock()
    {
        LeaveCriticalSection(&m_criticalSection);
    }

private:
    CRITICAL_SECTION m_criticalSection;
};

上述类没有什么特别之处

  • 它在构造时初始化临界区,
  • 它删除临界区,
  • `lock()` 方法锁定临界区,并且
  • `unlock()` 方法解锁临界区。

我们将使用临界区,但任何同步原语都适用。

Lock 类

为了与 C++ 既定的代码实践保持一致,我们需要一个特殊的类来实现 RAII(资源获取即初始化)模式。以下代码片段展示了这样一个类:

//synchronization controller object
class Lock
{
public:
    //the default constructor
    Lock(Mutex &mutex) : m_mutex(mutex), m_locked(true)
    {
        mutex.lock();
    }

    //the destructor
    ~Lock()
    {
        m_mutex.unlock();
    }

    //report the state of locking when used as a boolean
    operator bool () const
    {
        return m_locked;
    }

    //unlock
    void setUnlock()
    {
        m_locked = false;        
    }

private:
    Mutex &m_mutex;
    bool m_locked;
};

需要注意的类中的事项:

  • 它在构造时锁定互斥锁,并且
  • 它在销毁时解锁互斥锁。

使用上述类非常简单:

Mutex mutex1;
...
Lock lock1(mutex1);
//synchronized code here

“synchronized” 宏

`synchronized` 语句可以编码为一个宏,如下所示:

#define synchronized(M)  for(Lock M##_lock = M; M##_lock; M##_lock.setUnlock())

其中,参数 `M` 是用于锁定的互斥锁变量。

使用“synchronized”宏的示例

以下代码片段展示了如何使用 synchronized 宏:它协调两个线程,将字母表打印到标准输出。如果没有同步,输出将不正确:

//thread count
int thread_count = 0;

//mutex
Mutex mutex1;

//example thread
DWORD CALLBACK thread_proc(LPVOID params)
{
    for(int i = 0; i < 10; ++i)
    {
        synchronized(mutex1)
        {
            for(char c = 'A'; c <= 'Z'; ++c)
            {
                cout << c;
            }
            cout << endl;
        }
    }
    thread_count--;
    return 0;
}

//main
int main()
{
    thread_count = 2;
    CreateThread(0, 0, thread_proc, 0, 0, 0);
    CreateThread(0, 0, thread_proc, 0, 0, 0);
    while (thread_count) Sleep(0);
    getchar();
    return 0;
}

工作原理

该宏利用 C++ 的 `for` 语句的特性来执行以下操作(按所示顺序):

  1. 初始化部分:定义一个局部 lock 变量,该变量锁定给定的互斥锁;lock 变量包含一个内部标志,该标志设置为 true。
  2. 测试部分:测试 lock 变量,发现为 true:执行循环内的代码。
  3. 递增部分:将 lock 变量的内部标志设置为 false。
  4. 测试部分:测试 lock 变量,发现为 false:退出循环。
  5. 退出部分:销毁 lock 变量,解锁互斥锁。

相对于经典 RAII 的优势

以这种方式编写 RAII 具有一些相对于传统方法的优势:

  • 它使代码更具可读性,
  • 它有助于避免声明 lock 变量,并且
  • 它将要同步的代码与同步范围绑定在一起。

注释

由于 `synchronized` 宏在销毁时会解锁其互斥锁,因此它是异常安全的。

© . All rights reserved.