演示线程运行的开始和完结

  • 可执行程序运行失去一个过程,过程中惟一的主线程启动,当主线程从 main 函数返回,整个进行完结。
  • 创立的子线程须要从一个初始函数开始运行,一旦函数执行结束,以后子线程完结。
  • 过程完结标记:主线程是否完结。如果主线程执行结束,则代表整个过程完结,个别状况下此时如果还有其它子线程未执行完,则子线程会被强行终止(例外:detach)。

thread

创立一个线程执行对象。

join

阻塞主线程(调用线程),直到子线程执行完结。

注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)

detach

将子线程和主线程的关联拆散,子线程可驻留零碎后盾独立持续运行,主线程无奈再取得主线程的控制权,即主线程完结,子线程也不会完结。当子线程完结时,由C++运行时库负责清理线程相干的资源。

注:须要保障在 joinable 返回 true 时应用(返回 false 时运行时抛出 std::system_error 异样)

joinable

判断一个线程对象是否可能调用 join() 或者 detach(),能够返回 true,不能够返回 false。

Test1: thread, join, joinable

#include <iostream>#include <thread>using namespace std;void thread_func(){    cout << "thread_func begin" << endl;    for (uint32_t i=0; i<10000; ++i)    { }    cout << "thread_func end" << endl;}int main(){    cout << "main begin" << endl;    thread my_thread(thread_func);    if (my_thread.joinable())   // 注: 调用 join 前须要 joinable 判断!!!     {        cout << "my_thread.joinable() " << my_thread.joinable() << endl;        my_thread.join();    }    cout << "my_thread.joinable() " << my_thread.joinable() << endl;    cout << "main end" << endl;    return 0;}

输入:

main beginmy_thread.joinable() 1thread_func beginthread_func endmy_thread.joinable() 0main end

Test2: detach

#include <iostream>#include <thread>using namespace std;void thread_func(){    cout << "thread_func begin" << endl;    for (uint32_t i=0; i<10000; ++i)    { }    cout << "thread_func end" << endl;}int main(){    cout << "main begin" << endl;    thread my_thread(thread_func);    if (my_thread.joinable())    {        my_thread.detach();    }    cout << "main end" << endl;    return 0;}

输入: 【过程完结,子线程后盾运行,无奈再在控制台输入】

main beginmain end

其它创立线程的办法

线程参数是一个可调用对象。其中可调用对象蕴含:函数、函数指针、lambda表达式、std::bind创立的对象、std::function创立的对象以及重载了函数调用运算符的类对象。

#include <iostream>#include <thread>using namespace std;void thread_func(){    cout << "thread_func begin" << endl;    for (uint32_t i=0; i<10000; ++i)    { }    cout << "thread_func end" << endl;}auto thread_lambda = []{    cout << "thread_lambda begin" << endl;    for (uint32_t i=0; i<10000; ++i)    { }    cout << "thread_lambda end" << endl;};class thread_class {public:    thread_class() {        cout << "thread_class " << this << endl;    }    thread_class(const thread_class&) {        cout << "thread_class(const thread_class&) " << this << endl;    }    ~thread_class() {        cout << "~thread_class() " << this << endl;    }    void operator () () {        cout << "thread_class begin" << endl;        for (uint32_t i=0; i<10000; ++i)        { }        cout << "thread_class end" << endl;    }};class base {public:    void func()    {        cout << "base::func begin" << endl;        for (uint32_t i=0; i<10000; ++i)        { }        cout << "base::func end" << endl;    }};int main(){    cout << "main begin" << endl;    cout << "function:" << endl;    thread my_thread1(thread_func);    if (my_thread1.joinable())        my_thread1.join();    cout << "lambda:" << endl;    thread my_thread2(thread_lambda);    if (my_thread2.joinable())        my_thread2.join();    cout << "class:" << endl;    thread_class tc;    thread my_thread3(tc);  // 留神:此处的线程对象中领有可调用类对象正本!!    if (my_thread3.joinable())        my_thread3.join();    cout << "class::function:" << endl;    base b;    thread my_thread4(&base::func, &b);    if (my_thread4.joinable())        my_thread4.join();    cout << "main end" << endl;    return 0;}

输入:

main beginfunction:thread_func beginthread_func endlambda:thread_lambda beginthread_lambda endclass:thread_class 0x62fde7thread_class(const thread_class&) 0x62fd77thread_class(const thread_class&) 0x6917f8~thread_class() 0x62fd77thread_class beginthread_class end~thread_class() 0x6917f8class::function:base::func beginbase::func endmain end~thread_class() 0x62fde7

阐明:

自定义可调用类对象测试代码中拷贝构造函数为什么被调用了两次?在测试环境QT5.15.2的STL源码中可见
// 1. thread 应用万能援用进行结构template<typename _Callable, typename... _Args>      explicit      thread(_Callable&& __f, _Args&&... __args)      {#ifdef GTHR_ACTIVE_PROXY    // Create a reference to pthread_create, not just the gthr weak symbol.    auto __depend = reinterpret_cast<void(*)()>(&pthread_create);#else    auto __depend = nullptr;#endif        _M_start_thread(_S_make_state(          __make_invoker(std::forward<_Callable>(__f),                 std::forward<_Args>(__args)...)),        __depend);      }      // 2. __make_invoker 应用 __make_invoker      template<typename _Callable, typename... _Args>      static _Invoker<__decayed_tuple<_Callable, _Args...>>      __make_invoker(_Callable&& __callable, _Args&&... __args)      {    return { __decayed_tuple<_Callable, _Args...>{        std::forward<_Callable>(__callable), std::forward<_Args>(__args)...    } };      }// 3. __decayed_tuple 是 tuple 别名,结构了 tuple 对象,产生一次拷贝结构template<typename... _Tp>      using __decayed_tuple = tuple<typename std::decay<_Tp>::type...>;      // 4. new _Impl{...},产生第二次拷贝结构template<typename _Callable>  static _State_ptr  _S_make_state(_Callable&& __f)  {using _Impl = _State_impl<_Callable>;return _State_ptr{new _Impl{std::forward<_Callable>(__f)}};  }
注:用可调用类对象创立的线程对象领有类对象的正本!!这将触发拷贝动作,性能可能是受损失的。