- STL庫跨平台;
- VS2010不支持
std::thread
庫,至少VS2012/2013及其以上可以;
一、庫概要
(1)std::thread
成員函數
thread(fun, args...); //構造函數,傳入函數,后面跟參數,若是類普通成員,需要加this指針作為參數1
void swap(thread& other); //線程交換
bool joinable() const; //是否可以加入
void join(); //線程加入線程
void detach(); //線程分離
std::thread::id get_id(); //獲取線程id
native_handle_type native_handle(); //獲取線程句柄
static unsigned int hardware_concurrency(); //檢測硬件並發特性,即最多運行的線程數目
當線程部阻塞運行時,主進程退出而子線程還在運行,則子線程不會退出,變成孤兒線程。
孤兒線程不會造成什么危害,操作系統會對其進行處理,但應盡量避免。
(2)線程中獲取線程id
- 使用
this_thread
命名空間;
this_thread::get_id(); //獲取當前線程的線程id
this_thread::yield();
this_thread::sleep_for();
this_thread::sleep_until();
二、應用示例
(1)創建線程
void fun_1()
{
while (true)
{
cout << "fun_1:" << this_thread::get_id() << endl;
}
}
void fun_2()
{
while (true)
{
cout << "fun_2:" << this_thread::get_id() << endl;
}
}
int main()
{
thread t_1(fun_1);
t_1.detach();
thread t_2(fun_2);
t_2.detach();
return 0;
}
(2)類成員作為線程入口 -- 類中創建線程
- 參數1必須要傳,表示當前對象,后面參數表示函數參數;
class TestClass
{
public:
void fun_1_thread_enter()
{
thread t_1(&TestClass::fun1, this, 123);
t_1.detach();
}
void fun_2_thread_enter()
{
thread t_2(&TestClass::fun2, this, 456);
t_2.detach();
}
private:
void fun1(int temp)
{
while (true)
{
cout << "TestClass::fun_1" << this_thread::get_id() << temp << endl;
}
};
void fun2(int temp)
{
while (true)
{
cout << "TestClass::fun_2" << this_thread::get_id() << temp << endl;
}
};
};
int main()
{
TestClass test_class;
test_class.fun_1_thread_enter();
test_class.fun_2_thread_enter();
while (true)
{
cout << "Main thread id:" << this_thread::get_id();
}
return 0;
}
(3)獲取CPU最高並發數目
unsigned int num = thread::hardware_concurrency();
(4)線程移動
- 下例,通過
move
函數移動線程1到線程2,線程2獲得線程1的所有屬性;
int main()
{
thread t_1(fun_1);
cout << "Thread 1 id:" << t_1.get_id() << endl;
thread t_2 = move(t_1);
cout << "Thread 2 id:" << t_2.get_id() << endl;
return 0;
}
(5)延時函數
- 使用
this_thread
命名空間中的sleep_for
或者sleep_until
函數實現等待; std::chrono
是一個時間庫;
this_thread.sleep_for(chrono::second(2)); //延時2s
this_thread::sleep_for(chrono::milliseconds(5000)); //延時5000ms
三、join
和detach
該項為新增項,在發現上文的錯誤后,新增第三項,而出現錯誤的原因是,上文參考了很多博客的文章,不是說所有博客的文章都是錯的,搜出來的文章很多都是重復或者轉載的,第一個寫相關文章的人也許是對的,但是隨着后來的人,尤其是一知半解的人,再加上自己的理解,難免出現一些偏差,要不是和同事討論這個問題,也許我都不會發現這個錯誤。記錄下來,作為教訓。
上文在修改前有一個錯誤,join()
和detach()
方法是對線程進行操作,不是開始線程,而在初始化結束后,線程已經開始。
看下這兩個函數的官方解釋:
void join();
Join thread
The function returns when the thread execution has completed.
This synchronizes the moment this function returns with the completion of all the operations in the thread: This blocks the execution of the thread that calls this function until the function called on construction returns (if it hasn't yet).
可見,是說,這個函數知道線程執行完成后才返回,即當調用join()
方法時,若線程函數正在執行,則阻塞,若線程函數已經執行完成,則返回。
void detach();
Detach thread
Detaches the thread represented by the object from the calling thread, allowing them to execute independently from each other.
Both threads continue without blocking nor synchronizing in any way. Note that when either one ends execution, its resources are released.
將該線程從創建線程中分離開,讓這兩個線程各自獨立的運行,且各自線程的資源由各自釋放。
綜上所述,join
和detach
方法時對線程進行操作,而不是作為線程的開始標志,當申請std::thread
資源結束的時候,線程已經開始執行。
那么join
還好說,會阻塞主線程,那么detach
方法的意義在哪?
如官方說明,這兩個線程會在執行結束后各自釋放各自的資源,即detach
的意義在於資源上。
- 若並行且不調用
detach
,則子線程並未從主線程分離,主線程結束后,子線程的資源得不到釋放,造成資源泄漏; - 使用
detach
方法,子線程從主線程分離,主線程結束不會關心子線程的狀況,子線程結束后,釋放子線程的資源;
當然,調用detach
方法也有風險,因為子線程從主線程中分離了,若整個程序的主線程都結束而其創建的子線程還在運行,則子線程就變成了孤兒線程。如何避免孤兒線程,相信這不是一個很困難的問題吧。