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. SQL server 数据库 操作及简单查询

    使用SQL Sever语言进行数据库的操作 常用关键字identity 自增长primary key 主键unique 唯一键not null 非空references 外键(引用) 在使用查询操作数 ...

  2. java zookeeper权限控制ACL(digest,IP)

    java zookeeper权限控制ACL(auth,digest,ip) 学习前请参考:https://www.cnblogs.com/zwcry/p/10407806.html zookeeper ...

  3. Dispose 与 close 方法 的区别

    Dispose : 释放 托管 与 非托管资源. Finalize : 释放 非托管资源. Close: 关闭资源后,可以再次使用资源.

  4. Metasploit – 内网连接

    0x00 问题描述 在渗透测试时,metasploit往往作为后渗透工具,(因为远程溢出越来越少).我一般都是在获得一个webshell后,来使用metasploit进行信息采集,或者内网扫描等操作. ...

  5. C# word 类库基本属性介绍

    using System;using System.Collections.Generic;using System.Text;using Microsoft.Office.Interop.Word; ...

  6. 2.scala控制结构、函数、异常处理

    2.scala控制结构.函数.异常处理---小书匠,在线编辑器,MARKDOWN,Evernote,文件版本 a:focus { outline: thin dotted #333; outline: ...

  7. JSP数据交互(一)

    1.JSP内置对象 请求对象:request 输出对象:out 响应对象:response 应用程序对象:application 会话对象:session 页面上下文对象:pageContext 页面 ...

  8. NumPy来自现有数据的数组

    NumPy - 来自现有数据的数组 这一章中,我们会讨论如何从现有数据创建数组. numpy.asarray 此函数类似于numpy.array,除了它有较少的参数. 这个例程对于将 Python 序 ...

  9. scala学习手记4 - Java基本类型对应的scala类

    在Java中变量类型分为两大类:基本类型和引用类型.虽然在JDK1.5以后引入了自动装箱和自动拆箱机制,大大减少了我们在直接类型和引用类型之间的纠结,但仍有一些我们不得不考虑的问题.比如我在工作遇到的 ...

  10. JNI_Z_03_类中的字段和方法的签名

    1. Java类型 相应的签名 例子 boolean Z byte B char C short S int I long L float F double D void V Object L用&qu ...