C++11中支持内置的thread库,此库兼容window和linux,在不同的平台都可以编译
实现线程并发
一个进程中可以存在并运行多个线程,其中有一个是主线程,当主线程结束后这个进程就结束了,所以要实现线程的并发,就要在主线程结束之间进行
创建线程的方法
- 传递一个普通函数
#include <iostream>
#include <thread>
#include <windows.h>
void func(const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
Sleep(1000);
}
std::cout << str << "线程执行完毕" << std::endl;
}
int main() {
std::cout << "主线程开始" << std::endl;
std::thread t1(func, "t1");
for (int i = 0; i < 10; i++) {
std::cout << "主线程\n";
Sleep(1000);
}
std::cout << "主线程结束" << std::endl;
t1.join();
return 0;
}
- 传递一个lambda函数
#include <iostream>
#include <thread>
#include <windows.h>
int main() {
std::cout << "主线程开始" << std::endl;
auto f = [](const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
Sleep(1000);
}
std::cout << str << "线程执行完毕" << std::endl;
};
std::thread t2(f, "t2");
for (int i = 0; i < 10; i++) {
std::cout << "主线程\n";
Sleep(1000);
}
std::cout << "主线程结束" << std::endl;
t2.join();
return 0;
}
- 传递一个仿函数
#include <iostream>
#include <thread>
#include <windows.h>
class MyThread {
public:
// 仿函数的书写要重写其()运算符
void operator()(const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
Sleep(1000);
}
std::cout << str << "线程执行完毕" << std::endl;
};
};
int main() {
std::cout << "主线程开始" << std::endl;
std::thread t3(MyThread(), "t3");
for (int i = 0; i < 10; i++) {
std::cout << "主线程\n";
Sleep(1000);
}
std::cout << "主线程结束" << std::endl;
t3.join();
return 0;
}
- 传递一个类的静态成员函数
#include <iostream>
#include <thread>
#include <windows.h>
class Mythread2 {
public:
static void func(const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
Sleep(1000);
}
std::cout << str << "线程执行完毕" << std::endl;
}
};
int main() {
std::cout << "主线程开始" << std::endl;
std::thread t4(Mythread2::func, "t4");
for (int i = 0; i < 10; i++) {
std::cout << "主线程\n";
Sleep(1000);
}
std::cout << "主线程结束" << std::endl;
t4.join();
return 0;
}
- 传递一个类的成员函数
#include <iostream>
#include <thread>
#include <windows.h>
class Mythread3 {
public:
void func(const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
Sleep(1000);
}
std::cout << str << "线程执行完毕" << std::endl;
}
};
int main() {
std::cout << "主线程开始" << std::endl;
Mythread3 thread3;
std::thread t5(&Mythread3::func, &thread3, "t5");
for (int i = 0; i < 10; i++) {
std::cout << "主线程\n";
Sleep(1000);
}
std::cout << "主线程结束" << std::endl;
t5.join();
return 0;
}
thread.join
上面创建线程如果不添加join,程序就有可能报错
原因就是,主线程和子线程不能确定谁先执行完。两个线程无论是哪个先执行完毕都导致程序异常终止。
因为主线程资源会在程序结束后被回收,而子线程不会被回收。
对于多线程程序中的线程资源一定要被回收,不然就会报错
线程执行join的作用是
将线程加入到线程队列中之前,主线程要等待子线程执行完毕之后才会执行
#include <iostream>
#include<thread>
using namespace std;
void myPrint()
{
for(int i=0; i<10; i++)
{
cout << "线程正在执行" <<i<<endl;
}
}
int main()
{
thread firstThread(myPrint);
firstThread.join();
for(int j =0;j<5;j++)
{
cout<<"主线程正在执行"<<j<<endl;
}
return 0;
}
输出结果:
- 如果去除了join方法,程序就会发生难以预测的错误
thread.detch()
子线程可以脱离主线程,两者并发执行,当主线程执行完毕之后,子线程将会被移动到C++运行时库管理,也就时放到了后台执行,这样不会时程序发生错误,但是子程序执行的结果不会出现在控制台
#include <iostream>
#include<thread>
using namespace std;
void myPrint()
{
for(int i=0; i<10000; i++)
{
cout << "线程正在执行" <<i<<endl;
}
}
int main()
{
thread firstThread(myPrint);
// firstThread.join();
firstThread.detach();
for(int j =0;j<5;j++)
{
cout<<"主线程正在执行"<<j<<endl;
}
return 0;
}
执行结果:
- 在子线程执行到803次循环时,主线程就结束了,所以后面的循环在控制台没有输出,这并不代表程序会在这里中断,说不定下次就能执行1000多次循环,这是未知的。
- (但是可以知道的是main函数中的循环结束后程序依然在执行,说明程序没有在此中断。
- 最后也没有因为主线程的结束而出现程序的错误,说明detach确实将子线程移动到了后台运行。
thread.joinable()
判断子线程能否加入到线程队列中
- 一般当线程执行join后不能再次执行join
- 在线程执行detach后不能再次执行join
#include <iostream>
#include<thread>
using namespace std;
void myPrint()
{
for(int i=0; i<10; i++)
{
cout << "线程正在执行" <<i<<endl;
}
}
int main()
{
thread firstThread(myPrint);
if(firstThread.joinable())
{
cout<<"子线程可以join"<<endl;
firstThread.join();
}
else
{
cout<<"子线程不能join"<<endl;
}
if(firstThread.joinable())
{
cout<<"子线程可以join"<<endl;
firstThread.join();
}
else
{
cout<<"子线程不能join"<<endl;
}
// firstThread.join();
// firstThread.detach();
for(int j =0;j<5;j++)
{
cout<<"主线程正在执行"<<j<<endl;
}
return 0;
}
执行结果:
pthread_cancle()
在window下的thread中无法对其进行操作
但在linux下的pthread库可以操作将子线程在主线程的运行状态下中断
#include <iostream>
#include <thread>
#include<pthread>
int main() {
std::cout << "主线程开始" << std::endl;
auto f = [](const std::string &str) {
for (int i = 0; i < 10; ++i) {
std::cout << str << "第[ " << i << " ]次执行 " << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
}
std::cout << str << "线程执行完毕" << std::endl;
};
thread t5(f, "t5");
std::this_thread::sleep_for(std::chrono::seconds(5));
pthread_t thid = t5.native_handle();
pthread_cancel(thid);
t5.join();
return 0;
}
因为子线程等待的时间是10秒,主线程等待的时间是5秒,按照常理子线程整个程序会等待10秒后停止执行
主线程可以通过使用pthread_cancle来终止子线程的执行,要传递的是子线程的id(注意:这里的id不能通过get_id来获取,这里的id指的是pthread_id,只能通过native_handle()函数来获取