• 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:不实用,不再进行优化。

  • 相关阅读:
    javascript--运算符
    线程池 的创建小列子,以及参数的介绍
    @SpringBootApplication注解
    SpringBoot 基础知识学习(二)——配置文件多环境配置
    springboot 配置文件读取的两种方式,以及使用到的注解解释
    用虚拟机安装了一台Linux系统,突然想克隆一台服务器,克隆后发现无法上网,如何解决?
    ---oracle 数据库的设计,PL/SQL(loop,for,if,case,while)
    xml的解析技术, 它们之间的区别?
    -----oracle优化之表分区
    --------oracle 的伪表和伪劣,简单的分页
  • 原文地址:https://www.cnblogs.com/DWVictor/p/15217827.html
Copyright © 2020-2023  润新知