程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++11 中的線程、鎖和條件變量(1)

C++11 中的線程、鎖和條件變量(1)

編輯:C++入門知識

線程

類std::thread代表一個可執行線程,使用時必須包含頭文件<thread>。std::thread可以和普通函數,匿名函數和仿函數一個實現了operator()函數的類)一同使用。另外,它允許向線程函數傳遞任意數量的參數。

  1. #include <thread> 
  2.   
  3. void func() 
  4. { 
  5.    // do some work 
  6. } 
  7.   
  8. int main() 
  9. { 
  10.    std::thread t(func); 
  11.    t.join(); 
  12.   
  13.    return 0; 
  14. } 

上例中,t 是一個線程對象,函數func()運行於該線程中。對join()函數的調用將使調用線程本例是指主線程)一直處於阻塞狀態,直到正在執行的線程t執行結束。如果線程函數返回某個值,該值也將被忽略。不過,該函數可以接收任意數量的參數。

  1. void func(int i, double d, const std::string& s) 
  2. { 
  3.     std::cout << i << ", " << d << ", " << s << std::endl; 
  4. } 
  5.   
  6. int main() 
  7. { 
  8.    std::thread t(func, 1, 12.50, "sample"); 
  9.    t.join(); 
  10.   
  11.    return 0; 
  12. } 

盡管可以向線程函數傳遞任意數量的參數,但是所有的參數應當按值傳遞。如果需要將參數按引用傳遞,那要向下例所示那樣,必須將參數用std::ref 或者std::cref進行封裝。

  1. void func(int& a) 
  2. { 
  3.    a++; 
  4. } 
  5.   
  6. int main() 
  7. { 
  8.    int a = 42; 
  9.    std::thread t(func, std::ref(a)); 
  10.    t.join(); 
  11.   
  12.    std::cout << a << std::endl; 
  13.   
  14.    return 0; 
  15. } 

該程序打印結果為43,但是如果不用std::ref把參數a進行封裝的話,輸出結果將為42.

除了join方法外,該線程類還提供了另外兩個方法:

swap:交換兩個線程對象的底層句柄。

Detach: 允許執行該方法的線程脫離其線程對象而繼續獨立執行。脫離後的線程不再是可結合線程你不能等待它們執行結束)。

  1. int main() 
  2. { 
  3.     std::thread t(funct); 
  4.     t.detach(); 
  5.   
  6.     return 0; 
  7. } 

有一點非常重要,如果線程函數拋出異常,使用常規的try-catch語句是捕獲不到該異常的。換句話說,以下的做法是不可行的:

  1. try 
  2. { 
  3.     std::thread t1(func); 
  4.     std::thread t2(func); 
  5.   
  6.     t1.join(); 
  7.     t2.join(); 
  8. } 
  9. catch(const std::exception& ex) 
  10. { 
  11.     std::cout << ex.what() << std::endl; 
  12. } 

要在線程間傳遞異常,你需要在線程函數中捕獲他們,將其存儲在合適的地方,比便於另外的線程可以隨後獲取到這些異常。

  1. std::mutex                       g_mutex; 
  2. std::vector<std::exception_ptr>  g_exceptions; 
  3.   
  4. void throw_function() 
  5. { 
  6.    throw std::exception("something wrong happened"); 
  7. } 
  8.   
  9. void func() 
  10. { 
  11.    try 
  12.    { 
  13.       throw_function(); 
  14.    } 
  15.    catch(...) 
  16.    { 
  17.       std::lock_guard<std::mutex> lock(g_mutex); 
  18.       g_exceptions.push_back(std::current_exception()); 
  19.    } 
  20. } 
  21.   
  22. int main() 
  23. { 
  24.    g_exceptions.clear(); 
  25.   
  26.    std::thread t(func); 
  27.    t.join(); 
  28.   
  29.    for(auto& e : g_exceptions) 
  30.    { 
  31.       try 
  32.       { 
  33.          if(e != nullptr) 
  34.          { 
  35.             std::rethrow_exception(e); 
  36.          } 
  37.       } 
  38.       catch(const std::exception& e) 
  39.       { 
  40.          std::cout << e.what() << std::endl; 
  41.       } 
  42.    } 
  43.   
  44.    return 0; 
  45. } 

想要知道更多的關於捕獲和傳遞異常的知識,可以閱讀這兩本書在主線程中處理輔助線程拋出的C++異常和怎樣在線程間傳遞異常。

在深入學習之前,有一點需要注意 &lt;thread&gt;頭文件在命名空間std::this_thread中提供了一些幫助函數:

  • get_id: 返回當前線程的id.
  • yield:在處於等待狀態時,可以讓調度器先運行其他可用的線程。
  • sleep_for:阻塞當前線程,時間不少於其參數指定的時間。
  • sleep_util:在參數指定的時間到達之前,使當前線程一直處於阻塞狀態。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved