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 = ;
}
~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 + ;
m_ConditionVar.notify_all();
} bool IsFull()
{
return (m_nTail + ) % 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 + ;
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 = ; i < ; i++)
{
//this_thread::sleep_for(chrono::seconds(2));
pQueue->Push(i);
}
} void fun2(CMsgQueue<int> *pQueue)
{
for (int i = ; i < ; 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;
}
C++11新特性之线程操作的更多相关文章
- c++ 11 线程池---完全使用c++ 11新特性
前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- 转:c++ 11 新特性
声 明:本文源自 Danny Kalev 在 2011 年 6 月 21 日发表的<The Biggest Changes in C++11(and Why You Should Care)&g ...
- c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载
百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...
- C++11新特性总结 (二)
1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...
- C++11新特性总结 (一)
1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...
- 在C++98基础上学习C++11新特性
自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...
- C++11新特性——range for
很多编程语言都有range for语法功能,自C++11起,终于将这个重要功能加入C++标准中.range for语句,可以方便的遍历给定序列中的每个元素并对其执行某种操作. 1.基本语法 for(d ...
- JDK新特性关于流操作部分
// array 工具类 可以用来快捷的将数组转化为list List<String> strings = Arrays.asList("zhongguo", &quo ...
随机推荐
- sql 转
- C++中的config设计
配置文件读写类,它要有以下这些方法: 1. 支持读入一个指定配置文件的能力 2. 支持随时加入一个配置项的能力 3. 足够强大,能够写入各种数据结构的配置信息 C++ 里,我们要存储这样的数据就使用 ...
- onerror事件
onerror 事件会在文档或图像加载过程中发生错误时被触发. 案例: <img onerror="this.onerror=null;this.src='/images/common ...
- Sybase:获取本月最后一天的日期的实现方法
Sybase:获取本月最后一天的日期的实现方法 Oracle中查询月底那天的日期的函数为:last_day(). 在ASE中没有对应的函数,在Oracle移植到Sybase的时候,需要手动编写函数来实 ...
- python 利用PIL库进行更改图片大小的操作
python 是可以利用PIL库进行更改图片大小的操作的,当然一般情况下是不需要的,但是在一些特殊的利用场合,是需要改变图片的灰度或是大小等的操作的,其实用python更改图片的大小还是蛮简单的,只需 ...
- Ubuntu 14.04上架IPSec+L2TP的方法
最简单的方法是使用脚本一步一步地进行配置.我用的是philplckthun写的脚本,修改了一下获取服务器IP的方法:脚本文件. 在ubuntu下运行: sh setup.sh 配置配置完成后,服务器端 ...
- 异步消息postEvent更新界面
其实就是和Qt::QueuedConnection时的信号槽一样,属于异步的. 1.新建QEvent子类 ①.头文件 #ifndef MYEVENT_H #define MYEVENT_H #incl ...
- Hardware Prefetcher
硬件预取选项,指CPU有硬件预取功能,在CPU处理指令或数据之前,它将这些指令或数据从内存预取到L2缓存中,借此减少内存读取的时间,帮助消除潜在的瓶颈,以此提高系统效能.通常情况下建议设置为Enabl ...
- 对拷 使用scp命令在两台linux上对拷文件或者文件夹
以前一直是在服务器上tar打包压缩,下载到本地电脑上,再上传到另外一台服务器上,再解压. 其实使用scp命令就可以直接对拷文件或者文件夹了. scp就是secure copy,是用来进行远程文件拷贝的 ...
- mysql——主键自动增长&唯一索引
首先说一下主键和唯一索引的区别 主键:一个数据库的一张表有且仅有一个主键,而且主键不能重复 唯一索引:一个数据库的一张表上唯一索引可以有多个,只是所在唯一索引上的值不能重复,这一点和主键一样 下面我们 ...