Linux下C++多執行緒程式設計(入門例項)
C++多執行緒程式設計視訊教程:https://pan.baidu.com/s/1qLhfl83NeacIfR8QUJefmw
提取碼:z9w1
C++多執行緒
多執行緒是多工處理的一種特殊形式,多工處理允許讓電腦同時執行兩個或兩個以上的程式。一般情況下,兩種型別的多工處理:基於程序和基於執行緒。
- 基於程序的多工處理是程式的併發執行。
- 基於執行緒的多工處理是同一程式的片段的併發執行。
多執行緒程式包含可以同時執行的兩個或多個部分。這樣的程式中的每個部分稱為一個執行緒,每個執行緒定義了一個單獨的執行路徑。
本教程假設您使用的是 Linux 作業系統,我們要使用 POSIX 編寫多執行緒 C++ 程式。POSIX Threads 或 Pthreads 提供的 API 可在多種類 Unix POSIX 系統上可用,比如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。
建立執行緒
下面的程式,我們可以用它來建立一個 POSIX 執行緒:
1 #include <pthread.h> 2 pthread_create (thread, attr, start_routine, arg)
在這裡,pthread_create建立一個新的執行緒,並讓它可執行。下面是關於引數的說明:
建立執行緒成功時,函式返回 0,若返回值不為 0 則說明建立執行緒失敗。
終止執行緒
使用下面的程式,我們可以用它來終止一個 POSIX 執行緒:
1 #include <pthread.h> 2 pthread_exit (status)
在這裡,pthread_exit用於顯式地退出一個執行緒。通常情況下,pthread_exit() 函式是線上程完成工作後無需繼續存在時被呼叫。
如果 main() 是在它所建立的執行緒之前結束,並通過 pthread_exit() 退出,那麼其他執行緒將繼續執行。否則,它們將在 main() 結束時自動被終止。
例項
以下簡單的例項程式碼使用 pthread_create() 函式建立了 5 個執行緒,每個執行緒輸出"Hello Runoob!":
1 #include <iostream> 2 // 必須的標頭檔案 3 #include <pthread.h> 4 5 using namespace std; 6 7 #define NUM_THREADS 5 8 9 // 執行緒的執行函式10 void* say_hello(void* args) 11 { 12 cout << "Hello Runoob!" << endl; 13 return 0; 14 } 15 16 int main() 17 { 18 // 定義執行緒的 id 變數,多個變數使用陣列 19 pthread_t tids[NUM_THREADS]; 20 for(int i = 0; i < NUM_THREADS; ++i) 21 { 22 //引數依次是:建立的執行緒id,執行緒引數,呼叫的函式,傳入的函式引數 23 int ret = pthread_create(&tids[i], NULL, say_hello, NULL); 24 if (ret != 0) 25 { 26 cout << "pthread_create error: error_code=" << ret << endl; 27 } 28 } 29 //等各個執行緒退出後,程序才結束,否則程序強制結束了,執行緒可能還沒反應過來; 30 pthread_exit(NULL); 31 }
使用 -lpthread 庫編譯下面的程式:
$ g++ test.cpp -lpthread -o test.o
現在,執行程式,將產生下列結果:
1 $ ./test.o 2 Hello Runoob! 3 Hello Runoob! 4 Hello Runoob! 5 Hello Runoob! 6 Hello Runoob!
以下簡單的例項程式碼使用 pthread_create() 函式建立了 5 個執行緒,並接收傳入的引數。每個執行緒列印一個 "Hello Runoob!" 訊息,並輸出接收的引數,然後呼叫 pthread_exit() 終止執行緒。
例項
1 //檔名:test.cpp 2 3 #include <iostream> 4 #include <cstdlib> 5 #include <pthread.h> 6 7 using namespace std; 8 9 #define NUM_THREADS 5 10 11 void *PrintHello(void *threadid) 12 { 13 // 對傳入的引數進行強制型別轉換,由無型別指標變為整形數指標,然後再讀取 14 int tid = *((int*)threadid); 15 cout << "Hello Runoob! 執行緒 ID, " << tid << endl; 16 pthread_exit(NULL); 17 } 18 19 int main () 20 { 21 pthread_t threads[NUM_THREADS]; 22 int indexes[NUM_THREADS];// 用陣列來儲存i的值 23 int rc; 24 int i; 25 for( i=0; i < NUM_THREADS; i++ ){ 26 cout << "main() : 建立執行緒, " << i << endl; 27 indexes[i] = i; //先儲存i的值 28 // 傳入的時候必須強制轉換為void* 型別,即無型別指標 29 rc = pthread_create(&threads[i], NULL, 30 PrintHello, (void *)&(indexes[i])); 31 if (rc){ 32 cout << "Error:無法建立執行緒," << rc << endl; 33 exit(-1); 34 } 35 } 36 pthread_exit(NULL); 37 }
現在編譯並執行程式,將產生下列結果:
1 $ g++ test.cpp -lpthread -o test.o 2 $ ./test.o 3 main() : 建立執行緒, 0 4 main() : 建立執行緒, 1 5 Hello Runoob! 執行緒 ID, 0 6 main() : 建立執行緒, Hello Runoob! 執行緒 ID, 21 7 8 main() : 建立執行緒, 3 9 Hello Runoob! 執行緒 ID, 2 10 main() : 建立執行緒, 4 11 Hello Runoob! 執行緒 ID, 3 12 Hello Runoob! 執行緒 ID, 4
向執行緒傳遞引數
這個例項演示瞭如何通過結構傳遞多個引數。您可以線上程回撥中傳遞任意的資料型別,因為它指向 void,如下面的例項所示:
例項
1 #include <iostream> 2 #include <cstdlib> 3 #include <pthread.h> 4 5 using namespace std; 6 7 #define NUM_THREADS 5 8 9 struct thread_data{ 10 int thread_id; 11 char *message; 12 }; 13 14 void *PrintHello(void *threadarg) 15 { 16 struct thread_data *my_data; 17 18 my_data = (struct thread_data *) threadarg; 19 20 cout << "Thread ID : " << my_data->thread_id ; 21 cout << " Message : " << my_data->message << endl; 22 23 pthread_exit(NULL); 24 } 25 26 int main () 27 { 28 pthread_t threads[NUM_THREADS]; 29 struct thread_data td[NUM_THREADS]; 30 int rc; 31 int i; 32 33 for( i=0; i < NUM_THREADS; i++ ){ 34 cout <<"main() : creating thread, " << i << endl; 35 td[i].thread_id = i; 36 td[i].message = (char*)"This is message"; 37 rc = pthread_create(&threads[i], NULL, 38 PrintHello, (void *)&td[i]); 39 if (rc){ 40 cout << "Error:unable to create thread," << rc << endl; 41 exit(-1); 42 } 43 } 44 pthread_exit(NULL); 45 }
當上面的程式碼被編譯和執行時,它會產生下列結果:
1 $ g++ -Wno-write-strings test.cpp -lpthread -o test.o 2 $ ./test.o 3 main() : creating thread, 0 4 main() : creating thread, 1 5 Thread ID : 0 Message : This is message 6 main() : creating thread, Thread ID : 21 7 Message : This is message 8 main() : creating thread, 3 9 Thread ID : 2 Message : This is message 10 main() : creating thread, 4 11 Thread ID : 3 Message : This is message 12 Thread ID : 4 Message : This is message
連線和分離執行緒
我們可以使用以下兩個函式來連線或分離執行緒:
1 pthread_join (threadid, status) 2 pthread_detach (threadid)
pthread_join() 子程式阻礙呼叫程式,直到指定的 threadid 執行緒終止為止。當建立一個執行緒時,它的某個屬性會定義它是否是可連線的(joinable)或可分離的(detached)。只有建立時定義為可連線的執行緒才可以被連線。如果執行緒建立時被定義為可分離的,則它永遠也不能被連線。
這個例項演示瞭如何使用 pthread_join() 函式來等待執行緒的完成。
例項
1 #include <iostream> 2 #include <cstdlib> 3 #include <pthread.h> 4 #include <unistd.h> 5 6 using namespace std; 7 8 #define NUM_THREADS 5 9 10 void *wait(void *t) 11 { 12 int i; 13 long tid; 14 15 tid = (long)t; 16 17 sleep(1); 18 cout << "Sleeping in thread " << endl; 19 cout << "Thread with id : " << tid << " ...exiting " << endl; 20 pthread_exit(NULL); 21 } 22 23 int main () 24 { 25 int rc; 26 int i; 27 pthread_t threads[NUM_THREADS]; 28 pthread_attr_t attr; 29 void *status; 30 31 // 初始化並設定執行緒為可連線的(joinable) 32 pthread_attr_init(&attr); 33 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 34 35 for( i=0; i < NUM_THREADS; i++ ){ 36 cout << "main() : creating thread, " << i << endl; 37 rc = pthread_create(&threads[i], NULL, wait, (void *)&i ); 38 if (rc){ 39 cout << "Error:unable to create thread," << rc << endl; 40 exit(-1); 41 } 42 } 43 44 // 刪除屬性,並等待其他執行緒 45 pthread_attr_destroy(&attr); 46 for( i=0; i < NUM_THREADS; i++ ){ 47 rc = pthread_join(threads[i], &status); 48 if (rc){ 49 cout << "Error:unable to join," << rc << endl; 50 exit(-1); 51 } 52 cout << "Main: completed thread id :" << i ; 53 cout << " exiting with status :" << status << endl; 54 } 55 56 cout << "Main: program exiting." << endl; 57 pthread_exit(NULL); 58 }
當上面的程式碼被編譯和執行時,它會產生下列結果:
1 main() : creating thread, 0 2 main() : creating thread, 1 3 main() : creating thread, 2 4 main() : creating thread, 3 5 main() : creating thread, 4 6 Sleeping in thread 7 Thread with id : 4 ...exiting 8 Sleeping in thread 9 Thread with id : 3 ...exiting 10 Sleeping in thread 11 Thread with id : 2 ...exiting 12 Sleeping in thread 13 Thread with id : 1 ...exiting 14 Sleeping in thread 15 Thread with id : 0 ...exiting 16 Main: completed thread id :0 exiting with status :0 17 Main: completed thread id :1 exiting with status :0 18 Main: completed thread id :2 exiting with status :0 19 Main: completed thread id :3 exiting with status :0 20 Main: completed thread id :4 exiting with status :0 21 Main: program exiting.
c++ 11 之後有了標準的執行緒庫:
1 #include <iostream> 2 3 #include <thread> 4 5 std::thread::id main_thread_id = std::this_thread::get_id(); 6 7 void hello() 8 { 9 std::cout << "Hello Concurrent World\n"; 10 if (main_thread_id == std::this_thread::get_id()) 11 std::cout << "This is the main thread.\n"; 12 else 13 std::cout << "This is not the main thread.\n"; 14 } 15 16 void pause_thread(int n) { 17 std::this_thread::sleep_for(std::chrono::seconds(n)); 18 std::cout << "pause of " << n << " seconds ended\n"; 19 } 20 21 int main() { 22 std::thread t(hello); 23 std::cout << t.hardware_concurrency() << std::endl;//可以併發執行多少個(不準確) 24 std::cout << "native_handle " << t.native_handle() << std::endl;//可以併發執行多少個(不準確) 25 t.join(); 26 std::thread a(hello); 27 a.detach(); 28 std::thread threads[5]; // 預設構造執行緒 29 30 std::cout << "Spawning 5 threads...\n"; 31 for (int i = 0; i < 5; ++i) 32 threads[i] = std::thread(pause_thread, i + 1); // move-assign threads 33 std::cout << "Done spawning threads. Now waiting for them to join:\n"; 34 for (auto &thread : threads) 35 thread.join(); 36 std::cout << "All threads joined!\n"; 37 }
之前一些編譯器使用 C++11 的編譯引數是-std=c++11
g++ -std=c++11 test.cpp -lpthread
原文連結:http://www.runoob.com/cplusplus/cpp-multithreading.html