C++11线程库

C++11提供的线程库的好处:可以跨平台 + 提供了原子类型的变量
C++11中最重要的特性就是对线程进行了支持,是的C++在并行编程时不需要依赖第三方库,而且 在原子操作中还引入了原子类的概念,要使用标准库中的线程,必须包含< thread >头文件。
在这里插入图片描述
注意:
1.线程是操作系统中的一个概念,线程对象可以关联一个线程,用来控制线程以及获取线程的状态。
2.当创建一个宣传对象后,没有提供线程函数,该对象实际没有对应任何线程
3.当创建一个线程后,并且给线程关联线程函数,该线程函数就被启动,与主线程一起运行。线程函数一般情况下可以按照一下三种方式提供:
函数指针,lambda表达式,函数对象(仿函数)
在这里插入图片描述

C++线程库通过构造一个线程对象来启动一个线程,该线程对象中就包含了线程运行时的上下文环境,比如:线程函数、线程栈、线程起始状态等以及线程ID等,所有操作全部封装在一起,最后在底层统一传递给_beginthreadex() 创建线程函数来实现 (注意:_beginthreadex是windows中创建线程的底层c函数)

// 使用lambda表达式作为线程函数创建线程
int main()
{
 	int n1 = 500;
 	int n2 = 600;
 	thread t([&](int addNum){
 								n1 += addNum;
 								n2 += addNum;
 							}, 500);
 
 	t.join();
 	std::cout << n1 << ' ' << n2 << std::endl;
 	return 0;
 }

在这里插入图片描述

//使用函数指针的方式来进行创建线程
void func(int val)
{
	cout<<val<<endl;
}
int main()
{
	//使用函数指针来创建线程
	thread t1(func,100);
	t1.join();
	return 0;
}
//使用仿函数,函数对象来创建线程
class TF
{
public:
	void func(int val)
	{
		cout<<val<<endl;
	}	
};
int main()
{
	thread t2(TF(),(200));
	t2.join();
	return 0;
}

在这里插入图片描述
在这里插入图片描述
线程执行过程:
在这里插入图片描述
线程函数参数:
注意:
在这里插入图片描述
启动了一个线程后,当这个线程结束的时候,如何去回收线程所使用的资源呢?thread库给我们两种选择:
加入式:join()
join():会主动地等待线程的终止。在调用进程中join(),当新的线程终止时,join()会清理相关的资源,然后返回,调用线程再继续向下执行。由于join()清理了线程的相关资源,thread对象与已销毁的线程就没有关系了,因此一个线程的对象每次你只能使用一次join(),当你调用的join()之后joinable()就将返回false了。

分离式:detach()
detach:会从调用线程中分理出新的线程,之后不能再与新线程交互。就是你和你女朋友分手,那之后你们就不会再有联系(交互)了,而她的之后消费的各种资源也就不需要你去埋单了(清理资源)。此时调用joinable()必然是返回false。分离的线程会在后台运行,其所有权和控制权将会交给
c++运行库。同时,C++运行库保证,当线程退出时,其相关资源的能够正确的回收。

在这里插入图片描述
注意:必须在thread对象销毁之前做出选择,这是因为线程可能在你加入或分离线程之前,就已经结束了,之后如果再去分离它,线程可能会在thread对象销毁之后继续运行下去。

原子性操作库:

在这里插入图片描述
在这里插入图片描述
C++98中传统的解决方式:可以对共享修改的数据可以加锁保护。

#include <iostream>
using namespace std;
#include <thread>
#include <mutex>
	std::mutex m;
	unsigned long sum = 0L;
	void fun(size_t num) 
{
 	for (size_t i = 0; i < num; ++i)
 	{
 		m.lock();
 		sum++;
 		m.unlock();
 	}
}
int main()
{
 	cout << "Before joining,sum = " << sum << std::endl;
 	thread t1(fun, 10000000);
 	thread t2(fun, 10000000);
 	t1.join();
 	t2.join();
 	cout << "After joining,sum = " << sum << std::endl;
 	return 0; 
 }

C++11使用原子类变量。

#include <iostream>
using namespace std;
#include <thread>
#include <atomic>
atomic_long sum{ 0 };
void fun(size_t num) {
 for (size_t i = 0; i < num; ++i)
 sum ++; // 原子操作
}
int main()
{
 cout << "Before joining, sum = " << sum << std::endl;
 thread t1(fun, 1000000);
 thread t2(fun, 1000000);
 t1.join();
 t2.join();
 
 cout << "After joining, sum = " << sum << std::endl;
 return 0; }

虽然加锁可以解决,但是加锁有一个缺陷就是:只要一个线程在对sum++时,其他线程就会被阻塞,会影响程序运行的效率,而且锁如果控制不好,还容易造成死锁。因此C++11中引入了原子操作。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值