C++11新特性之线程操作

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

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

  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;
}

C++11新特性之线程操作

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/120134.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • SQLServer 远程备份和恢复

    SQLServer 远程备份和恢复

  • jQuery数据类型总结建议收藏

    jQuery除了包含原生JS中的内置数据类型(built-indatatype),还包括一些扩展的数据类型(virtualtypes),如Selectors、Events等。1.StringS

    2021年12月21日
  • Html 设置整个页面的背景颜色

    Html 设置整个页面的背景颜色在index.css中添加body{background:#ffffff}设置颜色为白色也就是给index.html设置了body的颜色,然后就可以看到整个html页面的颜色就成了白色。

  • 大疆网上测评题库_大疆笔试题

    大疆网上测评题库_大疆笔试题大疆笔试的体验很好,没有很为难应聘者,还有着自己鲜明的特点,我认为值得一说,特此写笔经记录一下,顺便攒攒RP,第一次笔经就献给大疆啦~笔试网站是大疆自己搭建的(UI设计炒鸡好看!!!),我猜题目也是大疆HR团队自己出的。从这点来看,大疆对人才的把控很严格,必须是自己经手选出来的人。整套笔试题目共有90道题,给了1.5个小时完成,题型包括态度行为题、行业知识题、工作情景题,以及略有升级的行测题。其中…

  • 振动分析软件有哪些_excel控件按钮怎么控制图表

    振动分析软件有哪些_excel控件按钮怎么控制图表LightningChart是优化了GPU加速,硬件性能的制图组件,用于实时呈现超过10亿个数据点的海量数据。同时LightningChart是为了处理实时数据采集和处理而开发的,可有效利用CPU和内存资源。LightningChart包括广泛的2D,高级3D,Polar,Smith,3D饼/甜甜圈,地理地图和GIS图表以及适用于科学,工程,医学,航空,贸易,能源和其他领域的体绘制功能。当您想到振动分析时,您会想到什么?它正在成为结构工程中一种非常常见的识别方法,用于识别潜在的结构完整性问题,例如隐藏的物

    2022年10月15日
  • CString::ReverseFind()和CString::Find()区别「建议收藏」

    CString::ReverseFind()和CString::Find()区别「建议收藏」Find()是从左往右查找;ReverseFind()是从右边往左查找,但是他们返回的地址都是从左往右数的。示例:[cpp]#include“stdafx.h”#include”afx.h”intmain(intargc,char*argv){CStringstr=”abcdabcd”;inta=str.Find(‘b’);printf(“

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号