C++中实现类似Java的“synchronized”

C++中实现类似Java的“synchronized”

设计思路:通过区域锁和宏定义实现。

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

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

The Mutex class

下面的一段代码展示了一个具有lock/unlock语义的互斥类(在许多库中很常见):

//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()解锁临界区

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

为了与 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语句可以编码为这样的宏:

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

其中,参数M是用于lock的互斥变量。

以下代码显示了如何使用同步宏:它协调两个线程,在标准输出中打印字母表。没有同步,输出不正确:

//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;
}

该宏利用forC++ 语句的性质来执行以下操作(按显示的顺序):

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

与经典 RAII 相比的优势

使用这种方式对 RAII 进行编码比传统方法有一些优势:

  • 它使代码更具可读性,
  • 它有助于避免声明锁变量,以及
  • 它将要与同步范围同步的代码联系起来。

笔记

synchronized宏是异常安全的,因为它在销毁时解锁其互斥锁。

PS:不实用,不再进行优化。

posted @ 2021-09-02 11:01  DWVictor  阅读(836)  评论(0编辑  收藏  举报