赞
踩
std::thread 在 头文件中声明,因此使用 std::thread 时需要包含 头文件。
(1). 默认构造函数,创建一个空的 thread 执行对象。
(2). 初始化构造函数,创建一个 thread对象,该 thread对象可被 joinable,新产生的线程会调用 fn 函数,该函数的参数由 args 给出。
(3). 拷贝构造函数(被禁用),意味着 thread 不可被拷贝构造。
(4). move 构造函数,move 构造函数,调用成功之后 x 不代表任何 thread 执行对象。
注意:可被 joinable 的 thread 对象必须在他们销毁之前被主线程 join 或者将其设置为 detached.
std::thread 各种构造函数例子如下(参考):
#include <iostream> #include <utility> #include <thread> #include <chrono> void f1(int n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 1 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } void f2(int& n) { for (int i = 0; i < 5; ++i) { std::cout << "Thread 2 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } class foo { public: void bar() { for (int i = 0; i < 5; ++i) { std::cout << "Thread 3 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; class baz { public: void operator()() { for (int i = 0; i < 5; ++i) { std::cout << "Thread 4 executing\n"; ++n; std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } int n = 0; }; int main() { int n = 0; foo f; baz b; std::thread t1; // t1 is not a thread std::thread t2(f1, n + 1); // pass by value std::thread t3(f2, std::ref(n)); // pass by reference std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f std::thread t6(b); // t6 runs baz::operator() on object b t2.join(); t4.join(); t5.join(); t6.join(); std::cout << "Final value of n is " << n << '\n'; std::cout << "Final value of foo::n is " << f.n << '\n'; }
指向当前线程std::this_thread
例如std::this_thread::get_id()
get_id | 获取线程 ID。 |
---|---|
joinable | 检查线程是否可被 join。 |
join | Join 线程。 |
detach | Detach 线程 |
swap | Swap 线程 。 |
native_handle | 返回 native handle。 |
hardware_concurrency [static] | 检测硬件并发特性 |
注意:以下问题主要都是在detach情况下发生,join下不会发生。
线程(函数)的传入参数,引用&会失效,指针*还是会传递地址。
#include <iostream> #include <thread> #include <string> using namespace std; void myprint(const int &i, char *pmybuf){ //i并不是mavar的引用,实际是值传递 //推荐改为const int i cout<<i<<endl; //指针在detach子线程时,还是指向原来的地址。但是此时地址已经被主线程释放会报错 cout<< pmybuf <<endl; } int main(){ int mvar=1; int &mvary=mvar; char mybuf[]="this is a test"; thread my_thread(myprint, mvar, mybuf);//第一个参数是函数名,后两个参数是函数的参数 // my_thread.join();//等待子线程执行结束 my_thread.detach(); cout<<"I love China"<<endl; return 0; }
#include <iostream> #include <thread> #include <string> using namespace std; void myprint(const int i, const string &pmybuf){ //i并不是mavar的引用,实际是值传递 //推荐改为const int i cout<<i<<endl; //指针在detach子线程时,还是指向原来的地址。但是此时地址已经被主线程释放会报错 cout<< pmybuf <<endl; } int main(){ int mvar=1; int &mvary=mvar; char mybuf[]="this is a test"; //如果是隐式转换,会有可能主线程执行完还没进行转换 // thread my_thread(myprint, mvar, mybuf);//第一个参数是函数名,后两个参数是函数的参数 // 因此需要显式的转换,构造临时对象 thread my_thread(myprint, mvar, string(mybuf));//第一个参数是函数名,后两个参数是函数的参数 // my_thread.join();//等待子线程执行结束 my_thread.detach(); cout<<"I love China"<<endl; while(1); return 0; }
#include <iostream> #include <thread> #include <string> using namespace std; class A{ public: int m_i; A(int a):m_i(a){cout<<"构造函数执行"<<endl;} A(const A &a):m_i(a.m_i){cout<<"拷贝构造函数执行"<<endl;} ~A(){cout<<"析构函数调用"<<endl;} }; void myprint(const int i, const A &pmybuf){ cout<< &pmybuf <<endl; } int main(){ int mvar=1; int mysec=12; // 如果是隐式转换,转换过程在子线程中执行,会有可能主线程执行完还没进行转换 // 因此需要显式的转换,构造临时对象 // 在线程声明时立刻执行构造 // thread my_thread(myprint, mvar, mysec);//第一个参数是函数名,后两个参数是函数的参数 thread my_thread(myprint, mvar, A(mysec));//第一个参数是函数名,后两个参数是函数的参数 // my_thread.join();//等待子线程执行结束 my_thread.detach(); cout<<"I love China"<<endl; return 0; }
1、线程(函数)的传入参数,引用&会失效,指针*还是会传递地址。因为主线程如果销毁了变量内存,子线程的运行就会出错,因此尽量不要在detach()的线程中用传递主线程中的指针
2、为了防止主线程先结束,detach()的线程还没构造,调用构造的时候要显示的调用类的拷贝构造,即为了防止主线程先结束,只有复制一份内存才行
3、想要传递真正的引用需要使用std::ref(param_nanm)
thread thread_obj(func,std::ref(num))
#include <iostream> #include <thread> using namespace std; class A { public: mutable int m_i; //mutable关键字,任何情况下都可以修改变量。即使实在const中也可以被修改 A(int i) :m_i(i) {} }; void myPrint(const A& pmybuf) { pmybuf.m_i = 199; } int main() { A myObj(10); //myPrint(const A& pmybuf)中引用不能去掉,如果去掉会多创建一个对象 //const也不能去掉,去掉会出错 //即使是传递的const引用,但在子线程中还是会调用拷贝构造函数构造一个新的对象, //所以在子线程中修改m_i的值不会影响到主线程 //如果希望子线程中修改m_i的值影响到主线程,可以用thread myThread(myPrint, std::def(myObj)); //这样const就是真的引用了,myPrint定义中的const就可以去掉了,类A定义中的mutable也可以去掉了 //此时拷贝构造也只执行一次了 thread myThread(myPrint, myObj); myThread.join(); //myThread.detach(); cout << "Hello World!" << endl; }
#include <iostream> #include <thread> #include <memory> using namespace std; void myPrint(unique_ptr<int> ptn) { cout << "thread = " << std::this_thread::get_id() << endl; } int main() { unique_ptr<int> up(new int(10)); //独占式指针只能通过std::move()才可以传递给另一个指针 //传递后up就指向空,新的ptn指向原来的内存 //所以这时就不能用detach了,因为如果主线程先执行完,ptn指向的对象就被释放了 thread myThread(myPrint, std::move(up)); myThread.join(); //myThread.detach(); return 0; }
https://en.cppreference.com/w/cpp/thread/thread/thread
如果对您有帮助,就打赏一下吧O(∩_∩)O
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。