C++——多线程编程(二)std::mutex 线程同步、解决资源竞争问题
来源:互联网 发布:352空气净化器 知乎 编辑:程序博客网 时间:2024/05/29 14:12
前言
线程同步
这里的“同”不是同时、一起执行的意思,而是指协同、协助、互相配合。线程同步是指多个线程协同步调,按预定的先后次序进行运行。
线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B依言执行,再将结果给A;A再继续操作。
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其它线程也不能调用这个方法。
定义:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作,而其他线程又处于等待状态。
目前实现线程同步的方法有很多:
1、临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2、互斥量(Mutex):采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
3、信号量(Semaphore):它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4、事件(Event):通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作
下面我们来详细介绍一下C++中的线程同步方式。
参考:http://www.cnblogs.com/haippy/p/3237213.html
(一)< mutex>头文件
Mutex 又称互斥量,C++ 11中与 Mutex 相关的类(包括锁类型)和函数都声明在 < mutex> 头文件中,所以如果你需要使用 std::mutex,就必须包含 < mutex> 头文件。
Mutex 系列类(四种)
- std::mutex,最基本的 Mutex 类。
- std::recursive_mutex,递归 Mutex 类。
- std::time_mutex,定时 Mutex 类。
- std::recursive_timed_mutex,定时递归 Mutex 类。
Lock 类(两种)
- std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁。
- std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。
其他类型
- std::once_flag
- std::adopt_lock_t
- std::defer_lock_t
- std::try_to_lock_t
函数
- std::try_lock,尝试同时对多个互斥量上锁。
- std::lock,可以同时对多个互斥量上锁。
- std::call_once,如果多个线程需要同时调用某个函数,call_once 可以保证多个线程对该函数只调用一次。
(二)Mutex 系列类
1 std::mutex
std::mutex 是C++11中最基本的互斥量, std::mutex 对象提供了独占所有权的特性——即不支持递归地对 std::mutex 对象上锁,而 std::recursive_lock 则可以递归地对互斥量对象上锁。
1.1 std::mutex的成员函数
- 构造函数
std::mutex不允许拷贝构造,也不允许 move 拷贝,最初产生的 mutex 对象是处于 unlocked 状态的。 - lock()
调用线程将锁住该互斥量。
线程调用该函数会发生下面 3 种情况:
(1)如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用 unlock之前,该线程一直拥有该锁。
(2)如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。
(3)如果当前互斥量被当前调用线程锁住,则会产生死锁(deadlock)。 - unlock()
解锁,释放对互斥量的所有权。 - try_lock()
尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞。
线程调用该函数会出现线面 3 种情况:
(1)如果当前互斥量没有被锁住免责调用线程将该互斥量锁住,知道调用unlock之前,该线程一直拥有该锁。
(2)如果当前互斥量已经被其他线程锁住了,则当前调用线程返回 false ,而并不会被阻塞。
(3)如果当前互斥量被当前调用线程锁住,会产生死锁(deadlock)。
例子
#include <iostream> // std::cout#include <thread> // std::thread#include <mutex> // std::mutexvolatile int counter(0); // non-atomic counterstd::mutex mtx; // locks access to countervoid attempt_10k_increases() { for (int i=0; i<10000; ++i) { if (mtx.try_lock()) { // only increase if currently not locked: ++counter; mtx.unlock(); } }}int main (int argc, const char* argv[]) { std::thread threads[10]; for (int i=0; i<10; ++i) threads[i] = std::thread(attempt_10k_increases); for (auto& th : threads) th.join(); std::cout << counter << " successful increases of the counter.\n"; return 0;}
2 std::recursive_mutex
std::recursive_mutex 与 std::mutex 一样,也是一种可以被上锁的对象,但是和 std::mutex 不同的是,std::recursive_mutex 允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权,std::recursive_mutex 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),可理解为 lock) 次数和 unlock() 次数相同 。
除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同
3 std::time_mutex
- C++——多线程编程(二)std::mutex 线程同步、解决资源竞争问题
- Java多线程、并发时使用Synchronized(同步锁)解决资源竞争问题
- mutex, cond; 竞争, 同步问题
- 同步线程—Mutex
- 多线程(C++)同步Mutex
- 多线程(C++)同步Mutex
- Java多线程编程— 线程同步问题
- Linux C 多线程互斥锁及线程同步问题 (二)
- Pthread线程 —— 多线程同步 互斥锁(mutex)
- c++11多线程编程(五):使用mutex修复竞争
- 多线程竞争资源问题
- Windows多线程编程(4)同步对象——Mutex对象
- 多线程之线程同步Mutex
- LinuxC多线程编程第四篇:线程同步mutex
- LinuxC多线程编程第四篇:线程同步mutex
- c#.net多线程编程教学——线程同步
- java多线程(二)解决共享资源竞争
- C#多线程同步(二)【Mutex】
- CentOS 7 安装 MySQL
- IARPUninstallStringLauncher绕过UAC
- canvas 基础
- asp.net 发送邮件,带附件
- 得到一个字符串在另一个字符串中第一次出现的索引
- C++——多线程编程(二)std::mutex 线程同步、解决资源竞争问题
- 七大排序算法
- 二、usb子系统初始化
- 为什么数据库索引查询会快
- 极光推送和通知栏
- User Agent参数的各个字段
- 产品经理如何写出一看就想约的简历
- 利用一种装饰者模式来进行处理流操作
- 在csdn的第一篇博客