> 文章列表 > 1. C++使用Thread类创建多线程的三种方式

1. C++使用Thread类创建多线程的三种方式

1. C++使用Thread类创建多线程的三种方式

1. 说明

使用Thread类创建线程对象的同时就会立刻启动线程,线程启动之后就要明确是等待线程结束(join)还是让其自主运行(detach),如果在线程销毁前还未明确上面的问题,程序就会报错。一般都会选择等待线程执行结束,如果不等待线程,即让其与主线程分离自主运行,那必须保证线程结束之前,可访问数据的有效性。
注意:当主线程碰到了子线程调用join()函数,程序会阻滞在当前行等待,知道当前子线程执行结束才会继续执行下面的代码。如果有多个线程需要同时执行,需要将每个线程的join()函数放到主线程的最后,才能避免阻滞现象。

2. 创建线程

使用thread类创建线程,主要有三种方式:①使用普通函数创建,②使用自定义类创建,③使用Lambda表达式创建

2.1 使用普通函数创建

此种方式,只是将普通函数的名字传输到thread构造函数中,注意不要再函数名字后面带()。

#include <iostream>
using namespace std;#include <thread>void myPrint() 
{cout << "我的线程开始执行了..." << endl;cout << "我的线程执行完毕了..." << endl;
}int main()
{thread myThread(myPrint);//创建线程对象,并启动线程myThread.join();//等待子线程执行结束后,再执行下面的代码//myThread.detach();  //子线程与主线程分离,各自执行,互不影响(但子线程如果使用了主线程中的数据,当主线程结束后,子线程无法访问到数据时,会报错)std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;return 0;
}

2.2 使用自定义类创建

这种方法需要重载()运算符,把子线程需要执行的代码写到里面即可。而且此种方法将类对象名传输到thread类构造函数中后,实际上时调用了自定义类的拷贝构造函数复制了一份,线程执行结束后会调用自定义类的析构函数。

#include <iostream>
using namespace std;#include <thread>class background_task
{
public://构造函数background_task(){cout << "这里时构造函数...." << endl;}//拷贝构造函数background_task(const background_task& bg){cout << "执行了拷贝构造函数...." << endl;}//析构函数(此案例中析构函数被调用两次,具体解释在下面)~background_task(){cout << "执行了析构函数...." << endl;}//重载()运算符,将子线程需要执行的代码写入其中void operator()() const{//在这里写子线程要执行的代码cout << "我的线程开始执行...." << endl;cout << "我的线程执行结束了...." << endl;}
};int main()
{background_task f;//创建类对象(主线程结束后销毁此对象,会调用一次析构函数)thread my_thread(f);//创建线程对象,并启动线程(线程结束后,在子线程空间内通过拷贝构造函数创建的对象也会被销毁,也会调用一次析构函数)my_thread.join();std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;return 0;
}

程序输出结果:
1. C++使用Thread类创建多线程的三种方式

2.3 使用Lambda表达式创建

这种方式创建比较简单,但是子线程中的代码不易重复使用


#include <iostream>
using namespace std;#include <thread>int main()
{//使用lambda表达式创建线程thread my_thread([] {cout << "lambda表达式创建的线程开始执行....\\n" << endl;cout << "lambda表达式创建的线程执行结束....\\n" << endl;});my_thread.join();std::cout << "主线程收尾,最终主线程安全正常退出...\\n"<<endl;return 0;
}

3 扩展:

①:
子线程调用join()函数时,可以先使用joinable()函数判断是否能够加入,一个子线程只能加入一次,若能加入则返回true,否则返回false.

#include <iostream>
using namespace std;#include <thread>void myPrint() 
{cout << "我的线程开始执行了..." << endl;cout << "我的线程执行完毕了..." << endl;
}int main()
{thread myThread(myPrint);//创建线程对象,并启动线程if(myThread.joinable()){cout << "子线程能够使用join()或者detach()函数" << endl;myThread.join();//等待子线程执行结束后,再执行下面的代码}else{cout << "子线程不能够使用join()或者detach()函数" << endl;}std::cout << "主线程收尾,最终主线程安全正常退出..."<<endl;return 0;
}

②:
当有多个子线程需要同时进行时,最好将子线程的join()函数调用放到所有子线程的后面,这样能确保子线程之间不会等待


#include <iostream>
using namespace std;#include <thread>int main()
{//使用lambda表达式创建线程thread my_thread_1([] {cout << "lambda表达式创建的线程 1 开始执行....\\n" << endl;cout << "lambda表达式创建的线程 1 执行结束....\\n" << endl;});//my_thread_1.join();//如果在这里调用join,则子线程1执行结束后才能执行子线程2,因为join函数会阻塞后面的代码执行thread my_thread_2([] {cout << "lambda表达式创建的线程 2 开始执行....\\n" << endl;cout << "lambda表达式创建的线程 2 执行结束....\\n" << endl;});my_thread_1.join();my_thread_2.join();std::cout << "主线程收尾,最终主线程安全正常退出...\\n"<<endl;return 0;
}