一.基本用法
#include<iostream>
#include<thread>
using namespace std;
void show(const char str[], const int id)
// void show(const char *str, const int id)
{
cout << "线程 " << id + 1 << " :" << str << endl;
}
int main()
{
thread t1(show, "hello cplusplus!", 0);
t1.join();
thread t2(show, "你好,C++!", 1);
t2.join();
thread t3(show, "hello!", 2);
t3.join();
return 0;
}
#include <iostream>
#include <thread>
using namespace std;
void sayHello();
void show();
void method(int &a)//ref
{
a += 5;
cout <<a<<endl;
}
int main(int argc, char const *argv[]) {
int a = 0;
thread th1(&method,ref(a));//ref !!
thread th1_move = thread(move(th1));//move constructor,th1被转移到th1_move后th1被销毁,类似于剪切
th1_move.join();
thread t11 (&sayHello);
t11.join();
cout <<"world"<<endl;
cout<<"------------"<<endl;
//栈上
thread t1(show); //根据函数初始化执行
thread t2(show);
thread t3(show);
//线程数组
thread th[3]{thread(show), thread(show), thread(show)};
//堆上
thread *pt1(new thread(show));
thread *pt2(new thread(show));
thread *pt3(new thread(show));
//线程指针数组
thread *pth(new thread[3]{thread(show), thread(show), thread(show)});
return 0;
}
void sayHello()
{
cout<<"hello"<<endl;
}
void show()
{
cout << "hello cplusplus!" << endl;
}
在传递参数时候需要注意,thread使用的是参数的拷贝,因此要求可调度物和参数类型都支持拷贝构造。如果希望传递给线程引用值就需要使用ref库进行包装,同时保证被引用对象在线程执行期间一直存在,否则会引发未定义行为。
二.多线程传递参数:
#include<iostream>
#include<thread>
using namespace std;
void show(const char str[], const int id)
{
cout << "线程 " << id + 1 << " :" << str << endl;
}
int main()
{
thread t1(show, "hello cplusplus!", 0);
t1.join();
thread t2(show, "你好,C++!", 1);
t2.join();
thread t3(show, "hello!", 2);
t3.join();
return 0;
}
三.线程的join和detach
#include<iostream>
#include<thread>
#include<array>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
thread th = thread(show);
th.detach();//脱离主线程的绑定,主线程挂了,子线程不报错,子线程执行完自动退出。
//detach以后,子线程会成为孤儿线程,线程之间将无法通信。
cout << th.joinable() << endl;
//th.join(); //error
array<thread, 3> threads = { thread(show), thread(show), thread(show) };
for (int i = 0; i < 3; i++)
{
cout << threads[i].joinable() << endl;//判断线程是否可以join
threads[i].join();//主线程等待当前线程执行完成再退出
}
return 0;
}
注意:
无论在windows中还是Posix中,主线程和子线程的默认关系是:无论子线程执行完毕与否,一旦主线程执行完毕退出,所有子线程执行都会终止。这时整个进程结束或僵死,部分线程保持一种终止执行但还未销毁的状态,而进程必须在其所有线程销毁后销毁,这时进程处于僵死状态。线程函数执行完毕退出,或以其他非常方式终止,线程进入终止态,但是为线程分配的系统资源不一定释放,可能在系统重启之前,一直都不能释放,终止态的线程,仍旧作为一个线程实体存在于操作系统中,什么时候销毁,取决于线程属性。在这种情况下,主线程和子线程通常定义以下两种关系:
1、可会合(joinable):这种关系下,主线程需要明确执行等待操作,在子线程结束后,主线程的等待操作执行完毕,子线程和主线程会合,这时主线程继续执行等待操作之后的下一步操作。主线程必须会合可会合的子线程。在主线程的线程函数内部调用子线程对象的wait函数实现,即使子线程能够在主线程之前执行完毕,进入终止态,也必须执行会合操作,否则,系统永远不会主动销毁线程,分配给该线程的系统资源也永远不会释放。
2、相分离(detached):表示子线程无需和主线程会合,也就是相分离的,这种情况下,子线程一旦进入终止状态,这种方式常用在线程数较多的情况下,有时让主线程逐个等待子线程结束,或者让主线程安排每个子线程结束的等待顺序,是很困难或不可能的,所以在并发子线程较多的情况下,这种方式也会经常使用。
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
join()是个简单暴力的方法:新线程调用join()之后,主线程会一直等待新进程,直到新线程执行完毕(Waits for this thread to die)。
而detach()将本线程从调用线程中分离出来,允许本线程独立执行。分离线程没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。但是当主进程结束的时候,即便是detach出去的子线程不管有没有完成都会被强制杀死。
简言之,main()函数结束了线程对象就析构了,如果线程没执行完那就爆炸了。
所以调用join阻塞,等待线程执行完毕。
或者用detach放到后台,不过放到后台你就没法控制它了,这个时候该thread对象不代表任何线程体,joinable()=false。
四.lambda表达式和thread结合
#include<iostream>
#include<thread>
using namespace std;
int main()
{
auto fun = [](const char *str) {cout << str << endl; };
thread t1(fun, "hello world!");
t1.join();
thread t2(fun, "hello beijing!");
t2.join();
return 0;
}
五.线程交换
#include <iostream>
#include <thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
thread t2([]()
{
cout << "thread2" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl;
cout << "swap after:" << endl;
swap(t1, t2);//线程交换
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl;
t1.join();
t2.join();
return 0;
}
六.线程移动
#include <iostream>
#include <thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
thread t2 = move(t1);
cout << "thread2' id is " << t2.get_id() << endl;
t2.join();
return 0;
}
出处:C++11并发之std::thread: http://blog.csdn.net/liuker888/article/details/46848905。