C++多執行緒



多執行緒是多工處理的一種特殊形式,而多工處理允許計算機同時執行兩個或多個程式的功能。一般來說,多工處理有兩種型別:基於程序的和基於執行緒的。

基於程序的多工處理處理程式的併發執行。基於執行緒的多工處理處理同一程式片段的併發執行。

多執行緒程式包含兩個或多個可以併發執行的部分。程式的每個部分稱為一個執行緒,每個執行緒定義一個單獨的執行路徑。

在C++ 11之前,沒有對多執行緒應用程式的內建支援。相反,它完全依賴於作業系統提供此功能。

本教程假設您正在使用Linux作業系統,我們將使用POSIX編寫多執行緒C++程式。POSIX執行緒(或Pthreads)提供可在許多類Unix POSIX系統(例如FreeBSD、NetBSD、GNU/Linux、Mac OS X和Solaris)上使用的API。

建立執行緒

以下例程用於建立一個POSIX執行緒:

#include <pthread.h>
pthread_create (thread, attr, start_routine, arg) 

這裡,pthread_create建立一個新執行緒並使其可執行。此例程可以從程式碼中的任何位置呼叫任意次數。以下是引數的描述:

序號 引數及描述
1

thread

子例程返回的新執行緒的不透明唯一識別符號。

2

attr

可用於設定執行緒屬性的不透明屬性物件。您可以指定執行緒屬性物件,或使用NULL表示預設值。

3

start_routine

執行緒建立後將執行的C++例程。

4

arg

可以傳遞給start_routine的單個引數。它必須作為void型別的指標強制轉換傳遞。如果沒有要傳遞的引數,可以使用NULL。

程序可以建立的執行緒最大數量取決於實現。建立後,執行緒是同級的,可以建立其他執行緒。執行緒之間沒有隱含的層次結構或依賴關係。

終止執行緒

我們使用以下例程來終止POSIX執行緒:

#include <pthread.h>
pthread_exit (status) 

這裡pthread_exit用於顯式退出執行緒。通常,線上程完成其工作並且不再需要存在後,會呼叫pthread_exit()例程。

如果main()在它建立的執行緒之前完成並使用pthread_exit()退出,則其他執行緒將繼續執行。否則,當main()完成時,它們將被自動終止。

示例

此簡單的示例程式碼使用pthread_create()例程建立5個執行緒。每個執行緒列印一條“Hello World!”訊息,然後透過呼叫pthread_exit()終止。

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
   long tid;
   tid = (long)threadid;
   cout << "Hello World! Thread ID, " << tid << endl;
   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   int rc;
   int i;
   
   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

使用-lpthread庫編譯以下程式,如下所示:

$gcc test.cpp -lpthread

現在,執行您的程式,將得到以下輸出:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4

向執行緒傳遞引數

此示例演示如何透過結構體傳遞多個引數。您可以將任何資料型別傳遞給執行緒回撥,因為它指向void,如下例所示:

#include <iostream>
#include <cstdlib>
#include <pthread.h>

using namespace std;

#define NUM_THREADS 5

struct thread_data {
   int  thread_id;
   char *message;
};

void *PrintHello(void *threadarg) {
   struct thread_data *my_data;
   my_data = (struct thread_data *) threadarg;

   cout << "Thread ID : " << my_data->thread_id ;
   cout << " Message : " << my_data->message << endl;

   pthread_exit(NULL);
}

int main () {
   pthread_t threads[NUM_THREADS];
   struct thread_data td[NUM_THREADS];
   int rc;
   int i;

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout <<"main() : creating thread, " << i << endl;
      td[i].thread_id = i;
      td[i].message = "This is message";
      rc = pthread_create(&threads[i], NULL, PrintHello, (void *)&td[i]);
      
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

編譯並執行上述程式碼後,將產生以下結果:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message

連線和分離執行緒

我們可以使用以下兩個例程來連線或分離執行緒:

pthread_join (threadid, status) 
pthread_detach (threadid) 

pthread_join()子例程會阻塞呼叫執行緒,直到指定的'threadid'執行緒終止。建立執行緒時,其屬性之一定義它是可連線的還是分離的。只有作為可連線的建立的執行緒才能連線。如果將執行緒建立為分離的,則永遠無法連線它。

此示例演示如何使用Pthread join例程等待執行緒完成。

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

using namespace std;

#define NUM_THREADS 5

void *wait(void *t) {
   int i;
   long tid;

   tid = (long)t;

   sleep(1);
   cout << "Sleeping in thread " << endl;
   cout << "Thread with id : " << tid << "  ...exiting " << endl;
   pthread_exit(NULL);
}

int main () {
   int rc;
   int i;
   pthread_t threads[NUM_THREADS];
   pthread_attr_t attr;
   void *status;

   // Initialize and set thread joinable
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

   for( i = 0; i < NUM_THREADS; i++ ) {
      cout << "main() : creating thread, " << i << endl;
      rc = pthread_create(&threads[i], &attr, wait, (void *)i );
      if (rc) {
         cout << "Error:unable to create thread," << rc << endl;
         exit(-1);
      }
   }

   // free attribute and wait for the other threads
   pthread_attr_destroy(&attr);
   for( i = 0; i < NUM_THREADS; i++ ) {
      rc = pthread_join(threads[i], &status);
      if (rc) {
         cout << "Error:unable to join," << rc << endl;
         exit(-1);
      }
      cout << "Main: completed thread id :" << i ;
      cout << "  exiting with status :" << status << endl;
   }

   cout << "Main: program exiting." << endl;
   pthread_exit(NULL);
}

編譯並執行上述程式碼後,將產生以下結果:

main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Sleeping in thread
Thread with id : 0 .... exiting
Sleeping in thread
Thread with id : 1 .... exiting
Sleeping in thread
Thread with id : 2 .... exiting
Sleeping in thread
Thread with id : 3 .... exiting
Sleeping in thread
Thread with id : 4 .... exiting
Main: completed thread id :0  exiting with status :0
Main: completed thread id :1  exiting with status :0
Main: completed thread id :2  exiting with status :0
Main: completed thread id :3  exiting with status :0
Main: completed thread id :4  exiting with status :0
Main: program exiting.
廣告