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新特性之线程操作的更多相关文章

  1. c++ 11 线程池---完全使用c++ 11新特性

    前言: 目前网上的c++线程池资源多是使用老版本或者使用系统接口实现,使用c++ 11新特性的不多,最近研究了一下,实现一个简单版本,可实现任意任意参数函数的调用以及获得返回值. 0 前置知识 首先介 ...

  2. [转载] C++11新特性

    C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...

  3. 转:c++ 11 新特性

    声 明:本文源自 Danny Kalev 在 2011 年 6 月 21 日发表的<The Biggest Changes in C++11(and Why You Should Care)&g ...

  4. c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载

    百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...

  5. C++11新特性总结 (二)

    1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...

  6. C++11新特性总结 (一)

    1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...

  7. 在C++98基础上学习C++11新特性

    自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...

  8. C++11新特性——range for

    很多编程语言都有range for语法功能,自C++11起,终于将这个重要功能加入C++标准中.range for语句,可以方便的遍历给定序列中的每个元素并对其执行某种操作. 1.基本语法 for(d ...

  9. JDK新特性关于流操作部分

    // array 工具类 可以用来快捷的将数组转化为list List<String> strings = Arrays.asList("zhongguo", &quo ...

随机推荐

  1. Spring 配置log4j和简单介绍Log4J的使用

    Log4j 是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台.文件.GUI组件.甚至是套接口服务器.NT的事 件记录器.UNIX Syslog守护进程等 ...

  2. netty2---服务端和客户端

    客户端: package com.client; import java.net.InetSocketAddress; import java.util.Scanner; import java.ut ...

  3. 链接指示:extern "C"

    C++程序有时需要调用其他语言编写的函数,最常见的是调用C语言编写的函数.像所有其他名字一样,其他语言中的函数名字也必须在C++中进行声明,并且该声明必须指定返回类型和形参列表.对于其他语言编写的函数 ...

  4. iOS日常学习 - 让你的 Xcode8 继续使用插件

    本文转载,原文链接 随着 iOS10 的正式版即将发布,Xcode8 GM 也在发布会后放出,本文不会涉及到 Xcode8 有哪些更新,而是记录了如何让 Xcode8 继续支持 Plugin. 相信各 ...

  5. fabric动态获取远程目录列表

    #!/usr/bin/pythonfrom fabric.api import *env.user='root'env.hosts=['172.10.224.183','172.10.224.132' ...

  6. idea中git合并切换分支等操作

    https://blog.csdn.net/autfish/article/details/52513465

  7. LeetCode——Find the Difference

    LeetCode--Find the Difference Question Given two strings s and t which consist of only lowercase let ...

  8. Node.js 项目的配置文件

    在 Node.js 中可以通过process.env来访问当前的环境变量信息,比如: { PATH: '/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin', T ...

  9. CentOS 5 上使用yum同时安装32位和64位包的解决方法

    在centos上使用yum在线安装软件包的时候,有时候会同时安装32位和64位的包.并且在update的时候也会更新双份. 其实让yum只安装64位的包,只要在 /etc/yum.conf 中加个 e ...

  10. mac的一些配置

    1,基础知识 /etc/bashrc :是针对系统所有用户的全局变量,只有root用户才能修改这两个文件,对一般用户来说是他们是只读的.一般用户要想修改它们,可以在命令前加sudo,意思是以Root身 ...