C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针相关的知识,希望对你有一定的参考价值。
文章目录
C++ thread线程类
线程类thread,提供RAII式线程的创建和销毁。创建线程时传入线程要执行的代码段(函数、lamda表达式)和参数,thread析构函数会自动销毁线程。
C++线程库通过构造一个线程对象来启动一个线程,该线程对象中就包含了线程运行时的上下文环境,比如:线程函数、线程栈、线程起始状态等以及线程ID等,所有操作全部封装在一起,最后在底层统一传递给_beginthreadex() 创建线程函数来实现 (注意:_beginthreadex是windows中创建线程的底层c函数)。
std::thread()创建一个新的线程可以接受任意的可调用对象类型(带参数或者不带参数),包括lambda表达式(带变量捕获或者不带),函数(全局函数或者成员函数),函数对象。
线程启动:thread对象构造函数
通过全局函数构造
#include<iostream>
#include<thread>
#include <windows.h>
using std::cout;
using std::endl;
void threadRoute(int a, int b)
cout << "I am a new thread of " << std::this_thread::get_id() << endl;
cout << a + b << endl;
cout << "sleep start" << endl;
Sleep(3000);
cout << "sleep end" << endl;
int main()
int a = 10, b = 20;
cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
std::thread t(threadRoute, a, b);//thread对象构造函数指定线程执行函数
t.join();//线程等待,防止出现孤儿线程
system("pause");
VS上运行:
I am the main thread,and my thread id is 22368
I am a new thread of 11944
30
sleep start
sleep end
请按任意键继续. . .
通过lamda表达式构造
#include<iostream>
#include<thread>
using std::cout;
using std::endl;
int main()
int a = 10, b = 20;
cout << "I am the main thread,and my thread id is " << std::this_thread::get_id() << endl;
std::thread t([=]
cout << "I am a new thread of " << std::this_thread::get_id() << endl;
cout << a + b << endl;
);
t.join();//线程等待,防止出现孤儿线程
system("pause");
结果:
I am the main thread,and my thread id is 31056
I am a new thread of 25312
30
请按任意键继续. . .
通过函数对象构造
#include<iostream>
#include<thread>
using std::cout;
using std::endl;
struct funcClass
void operator()(int a, int b)
cout << "ID:" << std::this_thread::get_id() << endl;
cout << a + b << endl;
;
int main()
funcClass fc;//函数对象构造线程时候,必须先有函数对象,操作符不能是静态的
std::thread t(fc, 10, 20);
t.join();
system("pause");
return 0;
结果:
ID:29648
30
通过成员函数构造
#include <iostream>
#include <thread>
using namespace std;
struct A
static void memberFunc(int a, int b)
cout << "hello from class member function :" << this_thread::get_id() << endl;
cout << a + b << endl;
;
int main(int argc, char** argv)
thread t1(A::memberFunc, 10, 20);
t1.join();
system("pause");
return 0;
结果:
hello from class member function :32868
30
请按任意键继续. . .
线程结束
创建一个线程,默认状态是joinable状态,需要主线程等待,如果不希望去等待退出的线程,需要在线程退出之前使用线程对象的成员函数detach来线程分离。
加入式:join()
join():会主动地等待线程的终止。在调用进程中join(),当新的线程终止时,join()会清理相关的资源,然后返回,调用线程再继续向下执行。 由于join()清理了线程的相关资源,thread对象与已销毁的线程就没有关系了,因此一个线程的对象每次你只能使用一次join(),当你调用的join()之joinable()就将返回false了。
#include<iostream>
#include<thread>
using std::cout;
using std::endl;
void threadRoute()
cout << "ID:" << std::this_thread::get_id() << endl;
int main()
cout << "Main ID:" << std::this_thread::get_id() << endl;
std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
cout << t.joinable() << endl;//默认是joinable状态
t.join();//线程等待,防止出现孤儿线程
cout << t.joinable() << endl;//join一次就会把线程资源释放掉,现在已经是false了
system("pause");
结果:
Main ID:1652
ID:16668
1
0
分离式:detach()
detach:会从调用线程中分理出新的线程,之后不能再与新线程交互。 就像是你和你女朋友分手,那之后你们就不会再有联系(交互)了,而她的之后消费的各种资源也就不需要你去埋单了(清理资源)。此时调用joinable()必然是返回false。分离的线程线程变成了后台进程(孤儿进程),在Linux将由init接管,在c++中由库接管。
#include<iostream>
#include<thread>
#include<windows.h>
using std::cout;
using std::endl;
void threadRoute()
Sleep(3000);
cout << "ID:" << std::this_thread::get_id() << endl;
int main()
cout << "Main ID:" << std::this_thread::get_id() << endl;
std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
cout << t.joinable() << endl;//默认是joinable状态
t.detach();
cout << t.joinable() << endl;//detach函数会将线程分离,不需要主线程join
system("pause");
结果:
Main ID:27840
1
0
请按任意键继续. . . ID:20548
注意:必须在thread对象销毁之前做出选择,这是因为线程可能在你加入或分离线程之前,就已经结束了,之后如果再去分离它,线程可能会在thread对象销毁之后继续运行下去。
示例1:线程结束后再join
貌似不会报错,没啥影响
#include<iostream>
#include<thread>
#include<windows.h>
using std::cout;
using std::endl;
void threadRoute()
cout << "ID:" << std::this_thread::get_id() << endl;
int main()
cout << "Main ID:" << std::this_thread::get_id() << endl;
std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
cout << t.joinable() << endl;//默认是joinable状态 //1
Sleep(3000);
cout << t.joinable() << endl; //1
t.join();//线程等待,防止出现孤儿线程
cout << t.joinable() << endl;//join一次就会把线程资源释放掉,现在已经是false了 //0
system("pause");
结果:
Main ID:1948
1
ID:32100
1
0
请按任意键继续. . .
示例2:线程结束后再detach
貌似也没啥影响。。。。不会报错
#include<iostream>
#include<thread>
#include<windows.h>
using std::cout;
using std::endl;
void threadRoute()
cout << "ID:" << std::this_thread::get_id() << endl;
int main()
cout << "Main ID:" << std::this_thread::get_id() << endl;
std::thread t(threadRoute);//thread对象构造函数指定线程执行函数
cout << t.joinable() << endl;//默认是joinable状态
Sleep(3000);
t.detach();
cout << t.joinable() << endl;//detach函数会将线程分离,不需要主线程join
system("pause");
结果:
Main ID:4000
1
ID:8124
0
请按任意键继续. . .
线程安全的thread
thread对象可以转移所有权(?左值,move())
thread object is movable,not copyable,like std::unique_ptr
or std::ifstream
. std::move
并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而我们可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move
基本等同于一个类型转换:static_cast<T&&>(lvalue);
值得一提的是,被转化的左值,其生命期并没有随着左右值的转化而改变。如果期望std::move
转化的左值变量lvalue能立即被析构,那么肯定会失望了。
#include<iostream>
#include<thread>
using namespace std;
void some_function();
int main()
thread t1(some_function);
thread t2 = move(t1); //采用std::move移动语义将t1的所有权移动到t2,
//此时t2接管运行some_function(),而t1此时没有执行线程和其关联
t1 = thread(some_function); //t1仍然是左值
智能指针管理thread对象(?)
我们知道主线程创建新线程之后,主线程应该还需要去做其它事情而不仅仅是等待其它线程退出。主线程去做其它事情,在join函数之前,主线程可能会因为调用了其它函数而造成异常,这样主线程可能就错过join函数直接去异常处理了。因此,为了保证joinable状态的线程不会成为孤儿进程,可以将thread对象交给智能指针,智能指针析构函数中进行join。
#include<iostream>
#include<thread>
using std::cout;
using std::endl;
void threadRoute()//全局函数
cout << "ID:" << std::this_thread::get_id() << endl;
class Unique_ptr
public:
Unique_ptr(std::thread& t)//这里使用引用传参,传递的就是new出来的那一个线程对象
:pt(t)
~Unique_ptr()
if (pt.joinable())
pt.join();
Unique_ptr(const Unique_ptr&) = delete;
Unique_ptr operator=(const Unique_ptr&) = delete;
private:
std::thread& pt;
;
void func()
cout << "Main ID:" << std::this_thread::get_id() << endl;
std::thread t(threadRoute);
Unique_ptr pth(t);
//pth对象在此调用析构函数,调用线程join函数
int main()
func();
system("pause");
结果:
Main ID:18180
ID:29264
请按任意键继续. . .
以上是关于C++11多线程,线程对象(thread对象)joinable()join()detach()左值智能指针的主要内容,如果未能解决你的问题,请参考以下文章