zoukankan      html  css  js  c++  java
  • C++11新特性之线程操作

      C++11之前没有对并发编程提供语言级别的支持,这使得我们在编写可移植的并发程序时,存在诸多的不便。现在C++11增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高。

    1. 线程

    1.1 线程的创建

      #inclde <thread>

      std::thead t(ThreadFun, parm1, parm2,...);

      t.join();或t.detach();

      join会阻塞线程,直到线程函数结束

      detach让线程和线程对象分离,让线程作为后台线程去执行,但需要注意,detach之后就无法再和线程发生联系了,等于说失去了对线程的控制权。

    2. 互斥量

      C++11提供了以下4中语义的互斥量:

      std::mutex:独占互斥量,不能递归使用

      std::timed_mutex:带超时的独占互斥量,不能递归使用

      std::recursive_mutex:递归互斥量,不带超时功能

      std::recursive_timed_mutex:带超时的递归互斥量

    2.1 独占互斥量

      std::mutex m_mutex;

      mutex.lock();

      do something;

      mutex.unlock();

      注意:使用std::lock_guard<mutex> locker(m_mutex);可以简化lock/unlock的写法,同时也更安全,因为lock_guard在构造的时候会自动锁定互斥量,而在退出作用域后进行析构时就会自动解锁,从而保证了互斥量的正确操作。

      try_lock()尝试锁定互斥量,如果成功则返回true

    2.2 递归的独占互斥量

      需要注意的是尽量不要使用递归锁:

      (1)需要用到递归锁的多线程互斥处理本身就应该可以简化的,运行递归互斥很容易放纵复杂逻辑的产生

      (2)递归锁比起非递归锁要麻烦,效率低

      (3)递归锁虽然允许同一个线程多次获得同一个互斥量,可重复获得的最大次数并未具体说明,一旦超过一定次数会抛出std::system错误

    2.3 带超时的互斥量和递归带超时的互斥量

      std::timed_mutex比std::mutex多了两个超时获取锁的接口,try_lock_for和try_lock_until,这两个接口是用开设置获取互斥量的超时时间,使用时可以用一个while循环去不断地获取互斥量。

      std::timed_mutex mutex;

      std::chrono::secord timeout(2);

      if (mutex.try_lock_for(timeout))

        cout << "do work with the mutex" << endl;

      else:

        cout << "do work without the mutex" << endl;

    3. 条件变量 

    3.1 说明

      条件变量用于线程的同步机制,它能阻塞一个或多个线程,直到收到另外一个线程发出的同质或者超时,才会唤醒当前阻塞的线程。条件变量需要和互斥变量结合起来用。

      C++提供了两种条件变量:

      (1)condition_variable,配合std::unique_lock<std::mutex>进行wait操作

      (2)condition_variable_any,和任意带有lock,unlock语义的mutex搭配使用,比较灵活,但效率比condition_variable低

      注意以下函数的使用:

      (1)std::lock_guard,它利用了RAII机制可以保证mutex的安全释放

      (2)std::unique_lock与lock_guard的区别在与,前者可以自由地释放mutex,而后者需要等到std::lock_guard变量生命周期结束时才能释放。

    3.2 示例实现消息循环队列

     3.2.1 实现代码

    // 使用C++11的新特性实现线程安全的循环消息队列
    #pragma once
    
    #include<iostream>
    #include<mutex>
    #include<condition_variable>
    using namespace std;
    
    #define MAXQUEUELEN 32
    template<typename T>
    class CMsgQueue
    {
    public:
        CMsgQueue()
        {
            m_pQueue = new T[MAXQUEUELEN];
            m_nHead = m_nTail = 0;
        }
        ~CMsgQueue()
        {
            Clear();
        }
    
        void Push(T msg)
        {
            unique_lock<mutex> lock(m_Mutex);
            while (IsFull())
            {
                cout << "消息队列已经满,请等待..." << endl;
                m_ConditionVar.wait(lock);
            }
            cout << "Push: " << msg << endl;
            m_pQueue[m_nTail] = msg;
            m_nTail = m_nTail % MAXQUEUELEN + 1;
            m_ConditionVar.notify_all();
        }
    
        bool IsFull()
        {
            return (m_nTail + 1) % MAXQUEUELEN == m_nHead;
        }
        bool IsEmpty()
        {
            return m_nTail == m_nHead;
        }
        T Pop()
        {
            unique_lock<mutex> lock(m_Mutex);
            while (IsEmpty())
            {
                cout << "消息队列为空,请等待..." << endl;
                m_ConditionVar.wait(lock);
            }
            T msg = m_pQueue[m_nHead];
            cout << "Pop: " << msg << endl;
            m_nHead = m_nHead % MAXQUEUELEN + 1;
            m_ConditionVar.notify_all();
            return msg;
        }
        void Clear()
        {
            if (m_pQueue != NULL)
            {
                delete[] m_pQueue;
                m_pQueue = NULL;
            }
        }
    
    private:
        T *m_pQueue;
        int m_nHead;
        int m_nTail;
    
        mutex m_Mutex;
        condition_variable m_ConditionVar;
    };

    3.2.2 测试

    void fun1(CMsgQueue<int> *pQueue)
    {
        for (int i = 0; i < 40; i++)
        {
            //this_thread::sleep_for(chrono::seconds(2));
            pQueue->Push(i);
        }
    }
    
    void fun2(CMsgQueue<int> *pQueue)
    {
        for (int i = 0; i < 20; i++)
        {
            this_thread::sleep_for(chrono::seconds(2));
            pQueue->Pop();
        }
    }
    
    void main()
    {
        CMsgQueue<int> *pQueue = new CMsgQueue<int>;
        thread t1(fun1, pQueue);
        thread t2(fun2, pQueue);
    
        t1.join();
        t2.join();
    
        return;
    }

  • 相关阅读:
    Fiddler抓包9-保存会话(save)
    Selenium2+python自动化61-Chrome您使用的是不受支持的命令行标记:--ignore-certificate-errors
    Fiddler抓包8-打断点(bpu)
    Fiddler抓包7-post请求(json)
    Java图片验证码
    servlet过滤器
    servlet监听器实现在线人数统计
    基于MVC模式的数据库综合练习
    JSTL详解
    初识EL表达式
  • 原文地址:https://www.cnblogs.com/xiaobingqianrui/p/9047411.html
Copyright © 2011-2022 走看看