创建多线程 std::thread,join(),detach()

中文文档:原子操作std::atomic(可以无锁并发编程)

中文文档:线程支持库

参考:C++:线程(std::thread)

转载:C++多线程

一、std::thread创建多线程

点击查看代码
#include <iostream>
#include <thread>

void fun1()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "1" << "2" << std::endl;
	}
}
void fun2()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "3" << "4" <<  std::endl;
	}
}
int main() 
{
	std::cout << "main start" << std::endl;
	std::thread t1(fun1);
	std::thread t2(fun2);
	std::cout << "main end" << std::endl;

	return 0;
}

结果

可以看到,这样创建线程是有问题的,因为在创建了线程后线程开始执行,但是主线程main()并没有停止脚步,仍然继续执行然后退出,此时线程对象还是joinable(可结合的)的,线程仍然存在但指向它的线程对象已经销毁,所以会抛出异常。

二、如何保证子线程执行完了退出后再退出主线程呢?

1.使用join()

使用join接口可以解决上述问题,join的作用是让主线程等待直到该子线程执行结束(因此调用join会阻塞)。需要注意的是线程对象执行了join后就不再joinable了,所以只能调用join()一次。创建了线程之后并不是调用join或detach才会执行线程,也许调用join或detach之前线程已经执行完了。只要创建了线程对象(传递“函数名/可调用对象”作为参数的情况下),线程就开始执行(std::thread 有一个无参构造函数重载的版本,不会创建底层的线程,只是一个空的对象。)。

1)join()阻塞代码演示

点击查看代码
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;

void work()
{
	this_thread::sleep_for(chrono::seconds(5));
}

int main()
{
	clock_t start = clock();
	vector<thread> t;
	for (int i = 0; i < 5; i++)
	{
		t.emplace_back(thread(work));
		//t[i].join();  //join放在这里程序运行时间为25s多一点
	}
	for (int i = 0; i < 5; i++)
	{       //join放在这里程序运行时间为5s多一点
		t[i].join();  //join会阻塞住,因此需要放在创建线程的循环外边才能达到多线程的效果
	}
	cout << clock() - start;
}

2)join()使用演示

点击查看代码
#include <iostream>
#include <thread>

void fun1()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "1" << "2" << std::endl;
	}
}
void fun2()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "3" << "4" <<  std::endl;
	}
}

int main() 
{
	std::cout << "main start" << std::endl;
	std::thread t1(fun1);
	std::thread t2(fun2);
	std::cout << "***" << std::endl;
	t1.join();
	std::cout << "@@@" << std::endl;
	t2.join();
	std::cout << "main end" << std::endl;

        //std::thread(fun1).join();  //和上面两句代码等价
	return 0;
}

2. 使用detach()

detach是用来和线程对象分离的,这样线程可以独立地执行,不过这样由于没有thread对象指向该线程而失去了对它的控制,当对象析构时线程会继续在后台执行,但是当主程序退出时并不能保证线程能执行完。如果没有良好的控制机制或者这种后台线程比较重要,最好不用detach而应该使用join。

点击查看代码
#include <iostream>
#include <thread>

void fun1()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "1" << "2" << std::endl;
	}
}
void fun2()
{
	for (int i = 0; i < 10; i++)
	{
		std::cout << "3" << "4" <<  std::endl;
	}
}
int main() 
{
	std::cout << "main start" << std::endl;
	std::thread t1(fun1);
	std::thread t2(fun2);
	std::cout << "***" << std::endl;
	t1.detach();
	std::cout << "@@@" << std::endl;
	t2.detach();
	std::cout << "main end" << std::endl;

	return 0;
}

由结果可见线程并没有执行完而退出

三、std::thread调用含有参数,带有返回值的函数以及成员函数

std::thread调用带参数和返回值的函数

posted @ 2021-03-24 17:40  滴哒哒哒  阅读(338)  评论(0编辑  收藏  举报