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)


相关推荐

  • 安装HAXM「建议收藏」

    安装HAXM「建议收藏」老师给的是在网上下载HAXM。但事实上打开这里你会发现Android已经自动下载了HAXM因此你要做的是找到HAXM路径,然后继续安装它。我的路径是C:\Users\DELL\AppData\Local\Android\Sdk\extras\intel\Hardware_Accelerated_Execution_Manager…

  • 定时关机命令——shutdown

    定时关机命令——shutdown

  • java中dao层和service层的区别,为什么要用service?[通俗易懂]

    读了下面的文章让我豁然开朗我能不能理解ssh中service就相当于与jsp+servlet+dao中的servlet???转文:首先解释面上意思,service是业务层,dao是数据访问层。呵呵,这个问题我曾经也有过,记得以前刚学编程的时候,都是在service里直接调用dao,service里面就new一个dao类对象,调用,其他有意义的事没做,也不明白有这个有什么用,参加工作久了以

  • python爬虫–协程(初识)

    python爬虫–协程(初识)

  • python数组转化为字符串类型_python字符串类型

    python数组转化为字符串类型_python字符串类型python字符串数组转对象类型importjsoncontent=”'[{“_1″:”唐”,”_2″:12},{“_1″:”宋”,”_2″:2},{“_1″:”元”,”_2″:45}][{“_1″:”明”,”_2″:2},{“_1″:”清”,”_2″:4},{“_1″:”夏”,”_2″:5}][{“_1″:”商”,”_2″:11},{“_1″:”周”,”_2″:1},{“_1″:”晋”,”_2″:7}]”’#因为是字符串数组,一个字符串里含有三个数组,而每个数组里的对象都是以“,”隔开,

  • 利用模板导出文件(一)之XLSTransformer导出excel文件

    利用模板导出文件(一)之XLSTransformer导出excel文件由于现在好多公司都在实行办公无纸化操作,所以一般都是使用excel以及word来办公,本文是公司项目中使用excel文件模板生成对应的文件:首先,需要导入一下几个包:接下来就是具体的代码:importjava.io.File;importjava.io.IOException;importjava.util.ArrayList;importjava.util.Has

发表回复

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

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