首页 > C++多线程:互斥变量 std::mutex

C++多线程:互斥变量 std::mutex

文章目录

      • 描述
      • 成员函数
      • 总结

描述

  • 头文件
  • 使用 std::mutex
  • 简介

    mutex是一种多线程变成中的同步原语,它能够让共享数据不被多个线程同时访问,它不支持递归得对互斥对象上锁
  • 特点
    • 用方线程从它成功调用 lock 或 try_lock 开始,到它调用 unlock 为止占有 mutex
    • 线程占有 mutex 时,所有其他线程若试图要求 mutex 的所有权,则将阻塞(对于 lock 的调用)或收到 false 返回值(对于 try_lock )
    • 调用方线程在调用 lock 或 try_lock 前必须不占有 mutex ,否则无法获取变量

成员函数

  • 构造函数

    std::mutex::mutex

    constexpr mutex() noexcept;(1)
    mutex( const mutex& ) = delete;(2)
    

    (1)构造mutex实例,mutex实例构造完成之后是处于unlocked状态

    (2)mutex的拷贝构造函数是不存在的

  • std::mutex::~mutex析构函数

    销毁互斥变量

    若互斥为任何线程占有,或若任何线程在保有任何互斥的所有权时终止,则行为未定义

  • 赋值运算符,不存在

  • std::mutex::lock

    锁定互斥。若另一线程已锁定互斥,则到 lock 的调用将阻塞执行,直至获得锁

    错误发生时抛出 std::system_error ,包括底层操作系统阻止 lock 满足其规定的错误。在抛出任何异常的情况下,不锁定互斥。所以,直接使用mutex的lock成员是无处法处理异常的情况。

    #include 
    #include 
    #include 
    #include int g_num = 0;  // protected by g_num_mutex 共享数据
    std::mutex g_num_mutex;void slow_increment(int id) 
    { for (int i = 0; i < 3; ++i) { g_num_mutex.lock();++g_num;std::cout << id << " => " << g_num << '
    ';g_num_mutex.unlock();//chrono是C++的时间库,提供1s线程的休眠std::this_thread::sleep_for(std::chrono::seconds(1));}
    }int main()
    { //0号线程和1号线程交叉执行对全局变量g_num对累加操作,执行完成之后sleep 1秒std::thread t1(slow_increment, 0);std::thread t2(slow_increment, 1);t1.join();t2.join();
    }
    

    输出如下

    0 => 1
    1 => 2
    0 => 3
    1 => 4
    0 => 5
    1 => 6
    
  • std::mutex::try_lock

    尝试锁定互斥。立即返回。成功获得锁时返回 true ,否则返回 false。

    若此操作返回 true ,则同一互斥上的先前 unlock() 操作同步于(定义于 std::memory_order )它。注意若此操作返回 false ,则先前的 lock() 不与之同步

    #include 
    #include 
    #include 
    #include  // std::coutstd::chrono::milliseconds interval(100);std::mutex mutex;
    int job_shared = 0; // 两个线程都能修改 'job_shared',// mutex 将保护此变量int job_exclusive = 0; // 只有一个线程能修改 'job_exclusive'// 不需要保护// 此线程能修改 'job_shared' 和 'job_exclusive'
    void job_1() 
    { std::this_thread::sleep_for(interval); // 令 'job_2' 持锁while (true) { // 尝试锁定 mutex 以修改 'job_shared'if (mutex.try_lock()) { std::cout << "job shared (" << job_shared << ")
    ";mutex.unlock();return;} else { // 不能获取锁以修改 'job_shared'// 但有其他工作可做++job_exclusive;std::cout << "job exclusive (" << job_exclusive << ")
    ";std::this_thread::sleep_for(interval);}}
    }// 此线程只能修改 'job_shared'
    void job_2() 
    { mutex.lock();std::this_thread::sleep_for(5 * interval);++job_shared;mutex.unlock();
    }int main() 
    { /*可以看到job1中的实现,使用的是try_lock获取锁,因为刚开始job1线程会进行100毫秒的休眠,所以cpu会先去执行job2,但是job2使用的是lock成员所以在job2中sleep 500毫秒的过程中执行job1时try_lock返回false,则执行exclusive输出.当job2获取不到锁,job1休眠结束之后释放锁,则job1重新获取锁成功*/std::thread thread_1(job_1);std::thread thread_2(job_2);thread_1.join();thread_2.join();
    }
    

    输出如下

    job exclusive (1)
    job exclusive (2)
    job exclusive (3)
    job exclusive (4)
    job shared (1)
    
  • std::mutex::unlock解锁mutex实例

    使用前提是当前线程必须被mutex的实例锁定,否则改函数的调用是未定义的

    注意,当前成员与lock()成员,一般不直接调用,因为对异常情况的处理并不友好(程序锁定期间发生异常,进程就直接退出),所以一般与std::unique_lock 与 std::lock_guard 管理排他性锁 一起使用

    具体使用实例可以参考如上两个代码。

总结

mutex互斥变量,并提供来了独占锁特性。为C++提供了多线程访问共享数据的保护措施,同时引入了像unique_locklock_gurad异常处理锁机制来规避mutex的成员处理异常情况的不足。

更多相关:

  • 有时候因为业务需要,对某些非线程函数,比如mktime,需要使用互斥锁,可以参照example/blacklist-1或者channel_stats里面的用法 首先插件顶部声明 static TSMutex sites_mutex; 在TSPluginInit()中初始化 sites_mutex = TSMutexCreate...

  • 在编写ATS插件的过程中,发现使用mktime会偶尔出现段错误, 经过网上调研,发现mktime等函数不是线程安全的, 于是编写下面的代码进行测试. 注意加锁和不加锁区别很大, 在mktime中使用多线程, 加上互斥锁就没有问题. //gcc -g mktime_multithread.c -o mktime_multithr...

  • 经过长期探索,发现一个不需要手动设置线程休眠时间(e.g. std::this_thread::sleep_for(std::chrono::microseconds(1)))的代码: Github: https://github.com/log4cplus/ThreadPool #ifndef THREAD_POOL_H_7e...

  • nth_element(first,nth,last) first,last 第一个和最后一个迭代器,也可以直接用数组的位置。  nth,要定位的第nn 个元素,能对它进行随机访问. 将第n_thn_th 元素放到它该放的位置上,左边元素都小于它,右边元素都大于它. 测试代码: http://www.cplusplus.com...

  • c/c++老版本的rand()存在一定的问题,在转换rand随机数的范围,类型或者分布时,常常会引入非随机性。 定义在 中的随机数库通过一组协作类来解决这类问题:随机数引擎 和 随机数分布类 一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将(引擎和分布对象)定义为 st...

  • jsoncpp 是一个C++ 语言实现的json库,非常方便得支持C++得各种数据类型到json 以及 json到各种数据类型的转化。 一个json 类型的数据如下: {"code" : 10.01,"files" : "","msg" : "","uploadid" : "UP000000" } 这种数据类型方便我们人阅读以...

  • 问题如下: 已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子 集中的各个元素和为整数target的子集,结果中无重复的子集。 例如: nums[] = [10, 1, 2, 7, 6, 1, 5], target = 8 结果为: [[1, 7], [1, 2, 5], [2, 6], [1, 1, 6]] 同样之前有...

  • 通过multibranch类型的pipeline job使得对于多个branch的支持更加简单。只需要创建一个multibranch job,jenkins将自动地为所有的branch创建job。   文章来自:http://www.ciandcd.com文中的代码来自可以从github下载: https://github.com/c...

  • Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,MapReduce则为海量的数据提供了计算。 HDFS是Google File System(GFS)的开源实现,MapReduce是Google MapReduce的开源实现。 HDFS和MapReduce实现是完全分离的,并不是没有H...