C++11 多线程并发编程,thread,lock,lock_guard,unique_lock使用

0、thread的成员函数

myjob.join();//阻塞主线程,使得子线程执行完毕之后再执行主线程。
myjob.detach();//解除主线程与子线程的关系,两者独立执行,主线程执行完毕后会自动退出。

joinable();//用于检测线程是否joinable

joinable : 代表该线程是可执行线程。

not-joinable :通常一下几种情况会导致线程成为not-joinable

 1) 由thread的缺省构造函数构造而成(thread()没有参数)。

 2) 该thread被move过(包括move构造和move赋值)

 3) 该线程调用过join或者detach

detach方式下注意事项:

(1)detach()方式时,传指针如果主线程先执行完会发生错误,引用会拷贝不推荐使用。
(2)传递简单数据类型,建议值传递代替引用
(3)传递类对象,避免隐式类型转换,创建线程时使用显示类型转换,并且类对象中函数使用引用。
	//std::ref(A)作用:线程传对象时传递参数对象,不进行另外的拷贝

	//cout<<"main thread id is : "<<std::this_thread::get_id() << endl;//获取线程id

1、互斥量mutex类中有lock() 和unlock()函数、存在多个锁时,加锁顺序一致以防死锁
2、std::lock_guard为类模板,可以取代lock、unlock,可以自己释放锁
//lock_guard构造时调用lock(),析构时调用unlock()
3、std::lock(),锁住两个及两个以上的互斥量。一次加所有锁,要么全加锁要么不加锁。不存在加锁顺序导致死锁的问题
//示例:lock(mutex1,mutex2,…);
4、std::lock_guard()与std::lock()结合使用
//示例:
//std::lock(mutex1,mutex2);
//std::lock_guard guard(mutex1,std::adopt_lock);//使用adpot_lock参数,其为结构体对象
//std::lock_guard guard(mutex2,std::adopt_lock);//使用adpot_lock参数

5、unique_lock是类模板,比lock_guard()更灵活,效率相对低,内存占用高
5.1 初始化参数 adopt_lock(需要提前lock) adpot_lock参数使得构造时不调用mutex的lock函数
示例:

mutex1.lock();   
unique_lock<mutex> guard(mutex1,std::adopt_lock); 

5.2 初始化参数std::try_to_lock 在构造unique_lock时尝试加锁,加锁失败则返回,不会阻塞。使用时不能提前加锁
5.3 初始化参数std::defer_lock初始化没有加锁的mutex

6、unique_lock 成员函数
6.1 lock() 不用自己unlock()
6.2 unlock() 用户灵活解锁
6.3 bool try_lock() 尝试加非阻塞锁,加锁成功返回true,加锁失败返回false
6.4 release(),返回它所管理的mutex对象指针,并释放其所有权。解除mutex与unique_lock的联系
7、unique_lock的所有权传递,unique_lock的mutex可以转移,不能复制
//两个unique_lock间转移mutex所有权: unique_lock2(std::move(unique_lock1))
// 通过其他函数返回的unique_lock对象初始化 :

std::unique_lock<std::mutex> unique_lock2 = return_lock()//return_lock 返回另一个unique_lock对象

8、sleep 一些毫秒

std::chrono::milliseconds dura(2000);//2秒
std::this_thread::sleep_for(dura);//休息2秒

9、代码Demo

   #include <iostream>
    #include <thread>
    #include <vector>
    #include <queue>
    #include <mutex>
    
    using namespace std;
    
    
    void myprint(const int &i, char* pmybuf)
    {
    	cout << i << endl;
    	cout << "main thread id is : " << std::this_thread::get_id() << endl;
    	cout << pmybuf << endl;
    }
    class A
    {
    public:
    	int val;
    	A(int s):val(s)
    	{
    		cout << "构造" << endl;
    	}
    	~A()
    	{
    		cout << "析构" << endl;
    	}
    	void print(int num)
    	{
    		cout << "print num is :" << num << endl;
    	}
    };
    
    class B
    {
    private:
    	queue<int> que;
    	mutex my_mymutex;//互斥量
    private:
    	//删除元素
    	bool popCore(int &num)
    	{
    		my_mymutex.lock();//加锁
    		if (!que.empty())
    		{
    			num = que.front();
    			que.pop();
    			my_mymutex.unlock();//解锁
    			return true;
    		}
    		my_mymutex.unlock();//解锁
    		return false;
    	}
    	bool popCore2(int &num)
    	{
    		//std::lock_guard<mutex> guard(my_mymutex);//使用lock_guard
    		std::unique_lock<std::mutex> guard(my_mymutex);//使用unique_lock
    		
    		std::chrono::milliseconds dura(2000);//2秒
    		std::this_thread::sleep_for(dura);//休息2秒
    
    		if (!que.empty())
    		{
    			num = que.front();
    			que.pop();
    			return true;
    		}
    		return false;
    	}
    public:
    	//插入元素
    	void insert()
    	{
    		for (int i = 0; i < 1000; i++)
    		{
    			cout << "插入元素 i: " << i << endl;
    			std::unique_lock<std::mutex> guard(my_mymutex, std::try_to_lock);//使用unique_lock
    			
    			if (guard.owns_lock())
    			{
    				cout << "加锁成功" << endl;
    				que.push(i);
    			}
    			else
    				cout << "加锁失败" << endl;
    		}
    	}
    	//删除元素对外接口
    	void pop()
    	{
    		int num;
    		for (int i = 0; i < 1000; i++)
    		{
    			if (popCore2(num))
    				cout << "出队 数字 num :"<< num << endl;
    			else
    				cout << "que is NULL" << endl;
    		}
    	}
    };
    
    int main()
    { 
        /*
    	int num =10;
    	char[] buf = "this is a buf";
     	thread myjob(myprint,num,buf);//可调用函数、对象等,myprint为可调用函数,有参数的话后跟其参数
    
    	if (myjob.joinable())
    		cout << "join true1" << endl;
    	else
    		cout << "join false1" << endl;
    	myjob.join();//阻塞主线程,使得子线程执行完毕之后再执行主线程。
    	*/
    
    	/*  lamada表达式作为线程执行对象
    	auto mylamdathread = [] {
    		cout << "lamda thread bgein" << endl;
    		cout << "lamda thread end" << endl;
    	};
    	thread myjob2(mylamdathread);
    	myjob2.join();
    	cout << "hello" << endl;
    	*/
    
    	/*类成员函数指针做线程执行对象
    	A myobj(10);
    	thread myjob4(&A::print,myobj,20);
    	myjob4.join();
    	*/
    
    	/*创建多个线程,各子线程之间顺序靠操作系统调度
    	vector<thread> threads;
    	for (int i = 0; i < 10; i++)
    		threads.push_back(thread(print,i));
    
    	for (auto it = threads.begin(); it != threads.end(); ++it)
    		it->join();
    	*/
    
    	B b;
    	thread insert_thread(&B::insert, &b);
    	thread pop_thread(&B::pop, &b);
    	insert_thread.join();
    	pop_thread.join();
    	cout << "hello" << endl;
    	
    	return 0;
    }

条件变量condition_variable、wait、notify_one、notify_all

 #include <iostream>
    #include <thread>
    #include <vector>
    #include <queue>
    #include <mutex>
    
    using namespace std;
    
    class B
    {
    private:
    	queue<int> que;
    	mutex my_mymutex;//互斥量
    	std::condition_variable my_cond;//条件变量
    public:
    	//插入元素
    	void insert()
    	{
    		for (int i = 0; i < 1000; i++)
    		{
    			
    			std::unique_lock<std::mutex> guard(my_mymutex);//使用unique_lock
    			cout << "插入元素 i: " << i << endl;
    			que.push(i);
    			my_cond.notify_one();//通知一个线程唤醒wait的线程
    								 //notify_all()通知所有线程唤醒wait的线程,唤醒的多个线程争用锁
    
    		}
    	}
    	//删除元素对外接口
    	void pop()
    	{
    		int num = 0;
    		while (true)
    		{
    			std::unique_lock<std::mutex> guard(my_mymutex);
    			//wait()没有第二个参数或第二个参数返回false则解锁互斥量,阻塞;直到其他线程调用notify_one()函数
    			my_cond.wait(guard, [this] {//lambda表达式
    				if (!que.empty())
    					return true;
    				return false;
    			});
    			num = que.front();
    			que.pop();
    			guard.unlock();//灵活释放锁,可由unique_lock对象析构时释放
    			cout << "出队元素为:" <<num << endl;
    		}
    	}
    };
    
    int main()
    {
    	B b;
    	thread insert_thread(&B::insert, &b);
    	thread pop_thread(&B::pop, &b);
    	insert_thread.join();
    	pop_thread.join();
    	cout << "hello" << endl;
    
    	return 0;
    }

原子操作、std::async()使用

1、std::async为函数模板,返回std::future类对象 作用为创建异步任务

(1)参数std::launch::deferred表示任务等待get()或wait()时执行,延迟调用,不创建线程,主线程中执行
	示例:std::future<int> result = std::async(std::launch::deferred,mythread)
(2)参数std::launch::async调用async()时创建执行子线程异步执行
(3)std::launch::async | std::launch::deferred,首先创建新线程异步执行,创建失败时则延迟主线程执行

2、std::packaged_task 打包任务,类模板
示例:std::packaged_task<int(int)> mypt(mythread);

3、std::promise类模板,在某个线程中给它赋值,其他线程中可以使用

4、std::future result = std::async(mythread,10);

  std::future_status status = result.wait_for(std::chrono::seconds(1));//等待1s返回枚举类型

std::future_status:

(1)ready ,线程执行完毕

(2)timeout,超时,线程未执行完毕

(3)deferred,async的第一个参数设置为std::launch::deferred,由主线程延迟执行

5、可以定义为原子操作的运算符:++、–、+=、-=,&=、|=等

//定义全局变量
std::atomic<int> num;//原子操作对象

(1)atomic的load()函数以原子方式读 auto num2 (num.load());

(2)atomic的store()函数以原子方式写 num2.store(123);

 #include <iostream>
    #include <thread>
    #include <vector>
    #include <queue>
    #include <mutex>
    #include <future>
    using namespace std;
    
    //全局变量
    std::atomic<int> num;//原子操作对象
    
    int mythread(int num)
    {
    	cout << "thread begin, thread id is :" << std::this_thread::get_id() << endl;
    	std::chrono::milliseconds dura(2000);//休息2秒
    	std::this_thread::sleep_for(dura);
    	cout << "thread end" << endl;
    	return 5;
    }
    //promise类模板使用,在某个线程中给它赋值,其他线程中可以使用
    void func(std::promise<int> &temp, int calc)
    {
    	calc++;
    	calc *= 10;
    	std::chrono::milliseconds dura(2000);//休息5秒
    	std::this_thread::sleep_for(dura);
    	int result = calc;
    	temp.set_value(result);
    }
    
    //原子操作演示
    void addNum()
    {
    	for (int i = 0; i < 1000; i++)
    		num++;//atomic对象的操作是原子操作
    }
    
    int main()
    {
    	int num = 3;
    	cout << "main thread id is :" << std::this_thread::get_id() << endl;
    	
    	//1、std::async为函数模板,返回std::future类对象  作用为创建异步任务
    	std::future<int> result = std::async(mythread,num);//以mythread()为执行对象创建一个后台线程,此时不会阻塞
    	//std::future<int> result = std::async(mythread);//async(&A::func,&a,参数),
    													//A类的成员函数func做执行对象,a为A的对象,参数为func的参数
    	//2、(1)参数std::launch::deferred表示任务等待get()或wait()时执行
    		//延迟调用,不创建线程,主线程中执行
    		//示例:std::future<int> result = std::async(std::launch::deferred,mythread)
    		//(2)参数std::launch::async调用async()时创建执行子线程
    		//(3)std::launch::async | std::launch::deferred,首先创建新线程异步执行,创建失败时则延迟主线程执行
    
    	cout << result.get() << endl;//阻塞直到result返回结果,get函数只能调用一次
    	cout << "结束" << endl;
    	
    
    	/*
    	//3、std::packaged_task 打包任务,类模板
    		//std::packaged_task<int(int)> mypt(mythread);
    	std::packaged_task<int(int)> mypt([](int num) {//包装lambda表达式
    		cout << "thread begin, thread id is :" << std::this_thread::get_id() << endl;
    		std::chrono::milliseconds dura(1000);//休息1秒
    		std::this_thread::sleep_for(dura);
    		cout << "thread end" << endl;
    		return 5; 
    	});
    	std::thread t1(std::ref(mypt), 1);
    	t1.join();
    	std::future<int> result = mypt.get_future();
    
    	cout << result.get() << endl;
    	*/
    
    	/*
    	//std::promise类模板,在某个线程中给它赋值,其他线程中可以使用
    	std::promise<int> myprom;
    	std::thread t1(func,std::ref(myprom), 10);
    	t1.join();
    	std::future<int> result = myprom.get_future();
    	auto res = result.get();
    	cout << "result : " << res << endl;
    	cout << "结束" << endl;
    	*/
    
    
    	/*
    	//4、
    	std::future<int> result = std::async(mythread,10);
    	std::future_status status = result.wait_for(std::chrono::seconds(1));//等待1s返回枚举类型
    	if (status == std::future_status::timeout)//表示超时,线程未执行完
    	{
    		cout << "超时,线程未执行完" << endl;
    	}
    	else if (status == std::future_status::ready)//表示线程成功返回
    	{
    		cout << "线程执行完毕,返回" << endl;
    		cout << result.get() << endl;
    	}
    	else if (status == std::future_status::deferred)
    	{
    		//async的第一个参数设置为std::launch::deferred
    		cout << "线程延迟执行" << endl;
    		cout << result.get() << endl;
    	}
    	*/
    
    	/*
    	//5、shard_future 类模板,get()复制数据,可以get多次
    	std::packaged_task<int(int)> mypt(mythread);
    	std::thread t1(std::ref(mypt), 10);
    	t1.join();
    
    	std::future<int> result = mypt.get_future();
    	bool isValid = result.valid();
    	if(isValid)
    		cout<<"result valid"<<endl;
    	std::shared_future<int> shared_res(result.share()); //等价于std::move(result)
    	//上述5行可以代替为:
    		//std::shared_future <int > res(mypt.get_future());
    		
    	isValid = result.valid();
    	if (!isValid)
    	{
    		cout << "result unvalid" << endl;
    		isValid = shared_res.valid();
    		cout << "get result :" << shared_res.get() << endl;
    		cout << "get result :" << shared_res.get() << endl;
    		cout << "get result :" << shared_res.get() << endl;
    	}
    	*/
    
    	/*
    	//6、原子操作std::atomic
    		//全局变量num定义为atomic对象
    	thread t1(addNum);
    	thread t2(addNum);
    	t1.join();
    	t2.join();
    	cout << num << endl;
    	*/
    	return 0;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值