c++ 11 之后有了标准的线程库:std::thread。
参考thread库的使用
成员函数
构造函数
thread的构造函数有下面四个重载
默认构造函数
thread() noexcept
初始化构造函数
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
该函数使用可变参数模板来构造一个线程对象,用来代表一个新的可join的执行线程。这个执行线程通过可变参数传入线程函数对象fn,以及函数的参数列表(可以简单理解为通过传值的方式将参数传给该构造函数)
拷贝构造函数
thread (const thread&) = delete;
线程不支持拷贝构造
移动构造
thread(thread&&x) noexcept;
转移参数x所代表的可执行指令的所有权,而不会影响线程的执行,转移后,参数x不再代表任何执行线程。
析构函数
析构函数用于销毁线程,如果这个线程是可以join的,那么析构函数会调用terminate()函数来终止线程。在thread对象被销毁之前应该尽可能将其join或者detach,以防止执行线程因为对象销毁而终止。
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
void printtHelloWorld(){
while(true){
cout<<"hello world"<<endl;
sleep(1);
}
}
int main(){
thread t1(printtHelloWorld);
sleep(3);
t1.~thread();
return 0;
}
operator=
thread& operator= (thread&& rhs) noexcept;
thread& operator= (const thread&) = delete;
thread对象不允许拷贝构造,同样的对于赋值操作符的重载实质是移动赋值。
#include<iostream>
#include<thread>
using namespace std;
void printHelloWorld(){
cout<<"Hello World!"<<endl;
}
int main(){
thread t1;
t1 = thread(printHelloWorld);
t1.join();
return 0;
}
编译g++ test.cpp -std=c++11 -lpthread - o test
joinable
如果thread对象代表了一个执行线程,那么可以joinable。
C++中有几种情况不能joinable
- 默认构造
- 执行过move操作
- 执行过join或者detach
#include<iostream>
#include<thread>
using namespace std;
void printHelloWorld(){
cout<<"Hello World!"<<endl;
}
int main(){
thread t1;
if(!t1.joinable()){
cout<<"Thread is not joinable! (default constructor)"<<endl;
}
t1 = thread(printHelloWorld);
if(t1.joinable()){
cout<<"Thread is joinable! (represents a thread of execution)"<<endl;
t1.join();
if(!t1.joinable()){
cout<<"Thread is not joinable! (after call join())"<<endl;
}
}
thread t3;
thread t2(printHelloWorld);
t3 = move(t2);
if(!t2.joinable()){
cout<<"Thread is not joinable! (after move)"<<endl;
}
t3.join();
return 0;
}
Thread is not joinable! (default constructor)
Thread is joinable! (represents a thread of execution)
Hello World!
Thread is not joinable! (after call join())
Thread is not joinable! (after move)
Hello World!
join
线程执行完毕后函数返回,join函数可以用来阻塞调用此函数的线程,调用这个函数之后,线程对象将变成非joinable并且可以被安全销毁。
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
void pauseThread(int n){
sleep(n);
std::cout<<"pause of "<<n<<" seconds ended"<<std::endl;
}
int main(){
cout<<"spawing 3 threads..."<<endl;
std::thread t1(pauseThread,1);
std::thread t2(pauseThread,2);
std::thread t3(pauseThread,3);
cout<<"Done spawning threads. Now wait for them to join: "<<endl;
t1.join();
t2.join();
t3.join();
cout<<"All threads joined!"<<endl;
return 0;
}
detach
这个函数会将执行线程与调用线程分离,允许它们彼此独立运行,任意一个线程结束之后会释放拥有的资源。调用之后,线程对象会变成非joinable并且可以安全销毁。
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
void pauseThread(int n){
this_thread::sleep_for(chrono::seconds(n));
std::cout<<"pause of "<<n<<" seconds ended"<<std::endl;
}
int main(){
cout<<"spawing 3 threads..."<<endl;
std::thread (pauseThread,1).detach();
std::thread (pauseThread,2).detach();
std::thread (pauseThread,3).detach();
cout<<"Done spawning threads. (the main thread will now pause for 5 seconds)"<<endl;
pauseThread(5);
return 0;
}
创建方法
一般函数创建
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
void printtHelloWorld(){
while(true){
cout<<"hello world"<<endl;
sleep(1);
}
}
int main(){
thread t1(printtHelloWorld);
sleep(3);
t1.~thread();
return 0;
}
类的成员函数创建
类外创建
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
class SaySomething{
public:
void sayHello(){
cout<<"Hello World!\n";
}
void saySomething(string str){
cout<<str;
}
static void sayHelloStatic(){
cout<<"Hello static!\n";
}
};
int main(){
SaySomething sh;
thread t(&SaySomething::sayHello,&sh); //需要传入对象的地址
thread t1(&SaySomething::saySomething,&sh,"Hello cpp!\n"); //需要传入对象的地址和参数
thread t2(&SaySomething::sayHelloStatic); //静态成员函数不需要传入对象的地址,因为静态成员函数不属于对象
t.join();
t1.join();
t2.join();
return 0;
}
类内创建thread对象
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
class SaySomething{
private:
thread workThread;
void sayHello(){
cout<<"Hello world!\n";
}
public:
SaySomething(){
workThread=thread(&SaySomething::sayHello,this); //需要传入对象的地址
}
~SaySomething(){
workThread.join(); //等待线程结束,防止主线程退出时子线程被强制结束
}
};
int main(){
SaySomething saySomething; //Hello World!
return 0;
}
使用函数类创建
使用函数类创建
重载operator()来实现类似于函数的操作
#include<iostream>
#include<thread>
#include<unistd.h>
using namespace std;
class FunctionObject{
public:
void operator()(string str){
cout << str << endl;
}
void operator()(){
cout << "Hello World!\n";
}
};
int main(){
FunctionObject fo;
thread t(fo); //无参数版本
thread t1(fo, "Hello parameter!\n"); //有参数版本
t.join();
t1.join();
return 0;
}
lambda函数创建
#include<bits/stdc++.h>
using namespace std;
int main(){
thread t([]{
cout << "Hello from thread!" << endl;
});
t.join();
return 0;
}
function类创建
function类实例化的对象可以包装以下任何类型的可调用对象:函数、函数指针、指向成员函数的指针或者任何类型的函数对象(即,其类定义 operator()的对象,包括闭包)
#include<iostream>
#include<thread>
#include<unistd.h>
#include<functional>
using namespace std;
void add(int a,int b){
cout<<"Sum is: "<<a+b<<"\n";
}
int main(){
function<void(int,int)> f=add; //function类包装add函数
function<void(void)> f1 = bind(add,15,25); //function包装一个闭包
function<void(void)> f2 = [](){cout<<"from lambda"<<endl;};//function类包装一个lambda函数
thread t(f,10,20);
sleep(1); //需要传递参数,输出Sum is: 30
thread t1(f1);
sleep(1); //无需传参,输出Sum is: 40
thread t2(f2); //无需传参
t.join();
t1.join();
t2.join();
return 0;
}
bind的返回值创建
bind可以将函数和参数绑定为一个函数对象。
#include<iostream>
#include<thread>
#include<unistd.h>
#include<functional>
using namespace std;
void add(int a,int b){
cout<<"Sum is: "<<a+b<<"\n";
}
int main(){
auto f1 = bind(add,5,10);
f1(); // Sum is: 15
auto f2 = bind(add,placeholders::_1,placeholders::_2);
f2(10,20); // Sum is: 30
thread t1(f1);
thread t2(f2,20,30);
t1.join(); // Sum is: 15 来自线程的执行结果
t2.join(); // Sum is: 50 来自线程的执行结果
return 0;
}