在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
C++11之前没有对并发编程提供语言级别的支持,这使得我们在编写可移植的并发程序时,存在诸多的不便。现在C++11增加了线程以及线程相关的类,很方便地支持了并发编程,使得编写的多线程程序的可移植性得到了很大的提高。 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; } |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论