C++11多线程

互斥量:
std::mutex:独占的互斥量,不能递归使用
std::timed_mutex:带超时的独占互斥量,不能递归使用
std::recursive_mutex:递归互斥量,不带超时功能
std::recursive_timed_mutex:带超时的递归互斥量
这些互斥量的基本接口很相似,一般用法是通过lock()方法来阻塞线程,直到获得互斥量的所有权,在线程获得互斥量并完成任务后,必须使用unlock()来解除对互斥量的占用,lock()和unlock()必须成对出现,try_lock()尝试锁定互斥量,成功返回true,失败返回false,是非阻塞的。
//mutex的使用
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
std::mutex g_lock;
void func()
{
    g_lock.lock();

    std::cout<<"enter thread"<<std::this_thread::get_id()<<std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout<<"leave thread"<<std::this_thread::get_id()<<std::endl;
    g_lock.ulock();
}
//void func1()
//{
//  std::lock_guard<std::mutex> loker(g_lock);//出作用域后自动解锁

//  std::cout<<"enter thread"<<std::this_thread::get_id()<<std::endl;
//  std::this_thread::sleep_for(std::chrono::seconds(3));
//  std::cout<<"leave thread"<<std::this_thread::get_id()<<std::endl;
//}
int main()
{
    std::thread t1(func);
    std::thread t2(func);
    std::thread t3(func);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}
   使用lock_guard可以简化lock/ulock的使用,更加安全,其在构造时会自动锁定互斥量,在退出作用域后会自动进行析构,其使用见上面注释部分。
   递归互斥量std::recursive_mutex,允许同一线程多次获得该互斥锁,可以用来解决同一线程需要多次获取互斥量时的死锁问题,但是尽量避免使用该锁,原因如下:
    * 使用该锁本身是可以简化的,使用该锁容易引起更复杂逻辑的产生
    * 递归锁比起非递归锁,效率更低
    * 递归锁在一个线程内多次获得同一个互斥量,最大数并没有具体说明
   带超时的互斥量std::timed_mutex,在获取锁的时候增加超时等待功能,即设置获取互斥锁的等待时间,可以使用一个while循环来不断的获取该互斥量,其相比std::mutex()多了两个超时获取锁的接口:try_lock_for()和try_lock_until()。
//std::timed_mutex的使用
std::timed_mutex mutex;
void work() 
{
    std::chrono::milliseconds timeout(100);
    while(true){    //循环获取该锁
        if(mutex.try_lock_for(timeout)){
            //执行相应的操作
        }
    }
}   
条件变量:能阻塞一个或者多个线程,直到收到另外一个线程发出的通知或者超时,才唤醒当前阻塞的线程,条件变量需要和互斥量配合起来使用。
    1、condition_variable 配合std::unique_lock<std::mutex>进行wait的操作;
    2、condition_variable_any和任意带有lock、unlock语义的mutex搭配使用,比较灵活,但效率比condition_variable差一些;
    其使用过程如下:
        a、拥有条件变量的线程获取互斥量;
        b、循环检查某个条件,如果条件不满足则阻塞直到条件满足,然后向下执行;
        c、某个线程满足条件执行完之后调用notify_one或notify_all唤醒一个或所有的等待线程;
    以下例子为利用条件变量实现一个同步队列,同步队列作为一个线程安全的数据共享区,经常用于线程之间数据读取,比如半同步半异步线程池的同步队列
#include <mutex>
#include <thread>
#include <condition_variable>
template<typename T>
class SyncQueue
{
    bool IsFull()const
    {
        return mqueue.size()==m_maxSize;
    }
    bool IsEmpty()const
    {
        return m_queue.empty();
    }
public:
    SyncQueue(int maxSize):m_maxSize(maxSize)
    {

    }
    void Put(const T& x)
    {
        std::lockguard<std::mutex> locker(m_mutex);
        while(IsFull)
        {
            cout<<"缓冲区已满,请等待..."<<endl;
            m_notFull.wait(m_mutex);
        }
        m_queue.push_back(x);
        m_notEmpty.notify_one();
    }
    void Take(T& x)
    {
        std::lock_guard<std::mutex> locker(mutex);
        while(IsEmpty())
        {
            cout<<"缓冲区空了,需要等待..."<<endl;
            m_notEmpty.wait(m_mutex);
        }
        x=m_queue.front();
        m_queue.pop_front();
        m_notFull.notify_one();
    }
    bool Empty()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.empty();
    }
    bool Full()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size()==m_maxSize;
    }
    size_t Size()
    {
        std::lock_guard<std::mutex> locker(m_mutex);
        return m_queue.size();
    }
    int count()
    {
        return m_queue.size();
    }
    private:
        std::list<T> m_queue;    //缓冲区
        std::mutex m_mutex;     //互斥量和条件变量结合起来使用
        std::condition_variable_any m_notEmpty;//不为空的条件变量
        std::condition_variable_any m_notFull;//没有满的条件变量
        int m_maxSize;            //同步队列最大的size
}
注意:wait函数中会释放mutex,然后处于等待状态,在被notify_one或notify_all唤醒后会先获取mutex,相当于lock_guard的mutex在释放之后又获取到.
原子变量:原子类型std::atomic<T>,可以使用任意类型为模板参数,使用原子变量就不需要使用互斥变量来保护该变量,下述为使用原子变量实现的计数器:
#include <atomic>

struct AtomicCounter{
    std::atomic<int> value;
    void increment()
    {
        ++value;
    }
    void decrement()
    {
        --value;
    }
    int get()
    {
        return value.load();
    }
}
call_once/once_flag的使用:
    能保证在多线程环境中某个函数仅被调用一次,可以用std::call_once来保证函数仅被调用一次,使用的时候需要一个once_flag作为call_once的入参。
//call_once在线程函数中的使用
std::once_flag flag;
void do_once()
{
    std::call_once(flag,[](){std::cout<<"called oncce"<<std::endl;});
}
异步操作:
    主要有:std::future,std::promise,std::package_task
    std::future作为异步结果的传输通道,可以很方便地获取线程函数的返回值;std::promise用来包装一个值,将数据和future绑定起来,方便线程赋值;std::package_task用来包装一个可以调用的对象,将函数和future绑定起来,以便异步调用。
    1、future用来访问异步操作的结果,可以通过查看future的状态(future_status)来获取操作的结果,future有一下三种状态:
        a)、Deferred:异步操作还没有开始
        b)、Ready:异步操作已经完成
        c)、Timeout:异步操作超时
  eg:std::future_status status;
     status=future.wait_for(std::chrono::seconds(1));
    获取future结果有3种方式:get、wait、wait_for,get等待异步操作结束并返回结果;wait只是等待异步操作完成,没有返回值;wait_for是超时等待返回结果。
    2、协助线程赋值的类std::promise
    std::promise将数据和
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小佐编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值