C++並行編程2
啟動線程
查看線程構造函數,接受一個返回值為void的函數。如下:
void do_some_work();
std::thread my_thread(do_some_work);
也可以接受一個重新定義操作符的類,如下:
class background_task
{
public:
void operator()() const
{
do_something();
do_something_else();
}
};
background_task f;
std::thread my_thread(f);
但是下面這樣使用是錯誤的,還以為是一個函數:
std::thread my_thread(background_task());
可以這樣使用:
std::thread my_thread((background_task());
std::thread my_thread{background_task()};
一個完全啟動的例子為:
#include <thread>
void do_something(int& i)
{
++i;
}
struct func
{
int& i;
func(int& i_):i(i_){}
void operator()()
{
for(unsigned j=0;j<1000000;++j)
{
do_something(i);
}
}
};
void oops()
{
int some_local_state=0;
func my_func(some_local_state);
std::thread my_thread(my_func);
my_thread.detach();
}
int main()
{
oops();
}
只要線程構造時,傳入了可執行代碼,那麼就開始執行,但是調用了detach,這樣主線程就不會等待子線程,子線程共享了變量some_local_state,這樣就導致非法訪問。因此就需要等待子線程。
等待線程
my_thread.detach()應該修改為my_thread.join();join()只能調用一次,如果調用過,那麼joinable()就return false。
異常處理
如果主線程還在做一些事情,那麼就有可能異常退出,這樣還是沒有等待子線程,我們就要進行異常處理。有兩種方法:
try
{
do_something_in_current_thread();
}
catch(...)
{
if(my_thread.joinable())
{
my_thread.join();
}
throw;
}
或者
class thread_guard
{
std::thread& t;
public:
explicit thread_guard(std::thread& t_):
t(t_)
{}
~thread_guard()
{
if(t.joinable())
{
t.join();
}
}
thread_guard(thread_guard const&)=delete;
thread_guard& operator=(thread_guard const&)=delete;
};
thread_guard g(my_thread);
do_something_in_current_thread();
後台運行線程
就是調用detach().應用場景是,比如word編輯,建立一個新的文檔就啟動一個線程,兩個文檔之間不需要等待,這樣就會後台運行線程。