C++_thread & mutex

本文详细介绍了C++中的多线程概念,包括线程的创建与管理、互斥量mutex的使用,如std::lock_guard、std::mutex、std::recursive_mutex等,以及条件变量condition_variable的wait和notify操作。此外,还讨论了原子操作atomic和future、async的相关内容,深入探讨了如何在多线程环境中实现同步和数据安全。
摘要由CSDN通过智能技术生成

1.thread – 线程 包含在std空间< thread>头文件中

1.1 常用得成员函数
  • get_id() – 获取线程id
  • joinable() – 判断线程是否可以等待加入
  • join() – 等待线程执行完成之后才返回
  • detach() – 将本线程从调用线程中分离出去,允许本线程独立运行,但是当主线程结束得时候,本线程即使没有结束也会被强制杀死,调用了detach之后得线程调用join是没有用得
  • yield – 线程放弃当前执行,操作系统调用别得线程执行
1.2 一个简单得创建线程得过程 – 编译得时候加上选项 -std=c++11

ps:pthread_create 创建线程得函数是C++ 98 的创建接口 只支持linux 而thread是c11的新特性

#include<iostream>
#include<thread>
using namespace std;

void func1()
{
   
	cout<<"func1 foo" <<endl;
}
void func2(int a, int b)
{
   
cout <<"func2 foo" <<"a ==" <<a <<"  b==" <<b <<endl;
}

class A
{
   
	public:
	static void func3(int a)
	{
   
		cout << "static func3 foo" <<endl;
	}
	void func4(int a)
	{
   
		cout << "static fun4 foo "<<endl;
	}
};
int main()
{
   
	std::thread t1(func1);
	t1.join();
	int a=10,b=20;
	std::thread t2(func2,a,b);
	t2.join();
	std::thread t3(&A::func3,a);
	t3.join();
	//A Aa; -- 切记此种用法是错误得,不能绑定到非静态成员函数
	//std::thread t4(Aa.func4,a);
	//t4.join();	
}

2. 互斥量 - - mutex 包含在std空间,< mutex >头文件中 用来处理多线程之间对共享区域的原子操作

2.1 – std::lock_guard() RAII(资源分配时初始化)

std::lock_guard类是为了mutex RAII调用的一套类模板。类模板除了构造函数和析构函数外没有其它成员函数,该模板的工作原理是在构造mutex对象的时候 调用构造函数的时候(对象创建的时候)进行加锁,在析构函数的时候(对象生命周期结束的时候)进行解锁处理,这样可以简化对互斥量的加锁和解锁的处理

2.2 独占的互斥量 不能递归操作 std::mutex
  • 构造函数 std::mutex不允许拷贝构造 ,不允许move拷贝,刚定义的mutex变量处于unlocked状态
  • lock() 调用线程将锁住该互斥量 会有三种情况 1. 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住 直到调用unlock() 2.如果当前互斥量被其他线程锁住那么线程调用lock函数将会被 阻塞 3. 如果当前互斥量被当前线程锁住,则会产生死锁,相当于一个线程里面调用了2次lock
  • try_lock 调用线程将锁住该互斥量 会有三种情况 1. 如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住 直到调用unlock() 2.如果当前互斥量被其他线程锁住那么线程调用lock函数,当前线程返回false, 不会阻塞 3. 如果当前互斥量被当前线程锁住,则会产生死锁,相当于一个线程里面调用了2次try_lock()
  • unlock() 解锁
2.3 带超时的独占互斥量,不能递归使用 std::time_mutex

*std::time_mutex比std::mutex 多了两个超时获取锁的接口 try_lock_for 和try_lock_until
try_lock_for 尝试在某个时间段内进行加锁

  1. 如果此时互斥量未被上锁,则获得改锁
  2. 如果此时互斥量已经被其他线程获取,则当前线程会阻塞,直到获得互斥量的锁,但是阻塞的时间不会超过传入的参数real_time,超时返回false
  3. 如果此时互斥量已经在当前线程获取了一次锁,则会产生死锁
    try_lock_until与try_lock_for类似只是不是时间段而是时间点
2.4 可递归使用的互斥量,不带超时功能 std::recursive_mutex

std::recursiev_mutex 允许同一线程获取多次该互斥锁,而不会产生死锁的问题

#include<iostream>
#include<thread>
#inlude<mutex>

class Complex
{
   
public:
	std::recursive_mutex mu;
	int i;
	Complex():i(0){
   }
	void mul(int x)
	{
   
		std::lock_guard<std::recursive_mutex> lock(mu);
		i*=x;
	}
	void div(int x)
	{
   
		std::lock_guard<std::recursive_mutex>lock(mu);
		i/=x;
	}
	void both(x, y)
	{
   
		std::lock_guard<std::recursive_mutex>lock(mu);
		mul(x);
		div(y);
	}

};
int main()
{
   
	Complex complex;
	complex.both(2,3);
	cout << "finish" <<endl;
	return 0;
}
2.5 可递归使用的互斥量,带超时功能 std::recursive_timed_mutex

结合了std::recursive_mutex和time_mutex两者的功能

2.6 lock_guard 和unique_lock的使用和区别

*unique_lock和lock_guard 都能实现自动的加锁和解锁处理,但是unique_lock更加的灵活,能实现更多的功能,因为unique_lock可以进行临时的加锁和解锁,不一定非等到析构函数
*

3. 条件变量 – 头文件< condition_variable >

使用条件变量一定要使用unique_lock,因为条件变量在wait的时候会先unlock然后进入休眠,但是lock_guard并无此接口

3.1 使用过程
  1. 拥有条件变量的线程获得互斥量
  2. 循环检测某个条件,如果条件满足则向下执行,如果不满足就则阻塞置条件满足的时候
  3. 某个线程满足条件执行完成之后使用notify_one 或notify_all唤醒一个或所有等待的线程
3.2 成员函数
1. wait
void wait (unique_lock<mutex>& lck);//只包含unique_lock对象
template <class Predicate>
//包含unique_lock对象和 Predicate条件变量
void wait (unique_lock<mutex>& lck, Predicate pred)

  • 工作原理

1.当前线程调用wait之后会进入休眠状态,并且在休眠之前会进行unlock互斥量(为什么使用unique_lock的原因),直到另外的线程调用notify_one 或者notify_all唤醒该线程,一旦线程获得notify则wait 函数会自动添加lock 同理不能使用lock_guard

2.如果wait没有第二个参数,则在第一次调用的时候默认条件不满足,释放互斥量并且阻塞到本行,直到某个线程nofity_one或notify_all为止 如果该线程在notify中被唤醒 无条件的执行下面的操作

3.如果wait有第二个参数 ,如果第二个参数的条件不满足,则线程会释放互斥量并进入阻塞状态,直到notify_ont和notify_all唤醒为止,被唤醒后,线程将尝试获取互斥量,如果得不到线程将会阻塞在这里,如果得到了,就判断第二个参数得条件是否满足 如果满足则继续执行下面得内容

ps:wait_for和wait_until 两者都可以加上一个时间(一个是时间段,一个是时间点,两者在线程获得唤醒之前和超时之前都会进入阻塞状态,如果被notify_one或则notify_all唤醒,或者到了超时时间了,也会进行唤醒),在wait的时候会释放锁并进

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值