多線程是多任務(wù)處理的一種特殊形式,而多任務(wù)處理是一種讓你的電腦能并發(fā)運行兩個或兩個以上程序的特性。一般有兩種類型的多任務(wù)處理:基于進(jìn)程的和基于線程的。
基于進(jìn)程的多任務(wù)處理是并發(fā)執(zhí)行的程序?;诰€程的多任務(wù)處理是并發(fā)執(zhí)行的程序的一部分。
多線程程序包含了可以并發(fā)運行的兩個或更多個程序部分。這樣程序中的每個部分稱為一個線程,并且每個線程都定義了一個單獨的執(zhí)行路徑。
C++ 不包含對多線程應(yīng)用程序的任何嵌入式支持。相反,它完全依賴于操作系統(tǒng)來提供此項功能。
本教程假設(shè)您正在使用的是 Linux 操作系統(tǒng),我們將要使用 POSIX 編寫 C++ 多線程程序。 POSIX 線程,或稱 Pthreads,它提供了在許多類 Unix 的 POSIX 系統(tǒng)(如 FreeBSD,NetBSD,GNU/Linux,Mac OS X 和 Solaris)中可用的 API。
我們使用下面的函數(shù)來創(chuàng)建一個 POSIX 線程:
#include <pthread.h>
pthread_create (thread, attr, start_routine, arg)
這里的 pthread_create 創(chuàng)建了一個新線程,并使其可執(zhí)行。這個函數(shù)可以在代碼中的任意位置調(diào)用任意次。
下面是詳細(xì)的參數(shù)說明:
參數(shù) | 描述 |
---|---|
thread | 新線程的不透明、唯一的標(biāo)識符,它由子函數(shù)返回。 |
attr | 一個不透明的屬性對象,可用于設(shè)置線程屬性。你可以指定一個線程的屬性對象,默認(rèn)值為 NULL。 |
start_routine | C++ 例程,線程一旦創(chuàng)建將會被執(zhí)行。 |
arg | 一個傳遞給 start_routine 的參數(shù)。它必須傳遞一個 void 類型指針的引用。如果沒有參數(shù)傳遞,默認(rèn)值為 NULL。 |
一個進(jìn)程可創(chuàng)建的最大線程數(shù)是依賴實現(xiàn)決定的。線程一旦創(chuàng)建,它們之間是對等的,而且也有可能創(chuàng)建其它的線程。線程之間沒有隱含的層次或依賴關(guān)系。
我們使用下面的函數(shù)來終止一個 POSIX 線程:
#include <pthread.h>
pthread_exit (status)
此處的 pthread_exit 用于顯式的退出一個線程。通常在線程已完成了其工作,并且沒有存在的必要的時候,調(diào)用 pthread_exit()
函數(shù)。
如果 main()
在其創(chuàng)建的線程之前終止,并且使用了 pthread_exit()
來退出線程,那么其線程將會繼續(xù)執(zhí)行。否則,當(dāng) main()
終止后,這些線程將會自動終止。
下面簡單的樣例代碼,用 pthread_create()
函數(shù)創(chuàng)建了 5 個線程。每個線程均打印 “Hello World!”,然后調(diào)用 pthread_exit()
函數(shù)終止了線程。
#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
現(xiàn)在執(zhí)行上面的程序,將會產(chǎn)生如下的結(jié)果:
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
下面的例子展示了如何通過一個結(jié)構(gòu)體傳遞多個參數(shù)。你可以在一個線程回調(diào)中傳遞任何數(shù)據(jù)類型,這是因為它指向 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);
}
當(dāng)上述代碼編譯和執(zhí)行后,將會有以下的結(jié)果:
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
下面的兩個函數(shù),我們可以用它們來連接或分離線程:
pthread_join (threadid, status)
pthread_detach (threadid)
pthread_join()
子例程會阻塞調(diào)用它的線程,一直等到其指定的 threadid 的線程結(jié)束為止。當(dāng)一個線程創(chuàng)建后,它的屬性決定了它是否是可連接的或可分離的。只有創(chuàng)建時屬性為可連接的線程才可以連接。如果創(chuàng)建的是一個可分離的線程,那么它永遠(yuǎn)不能連接。
下面的例子演示了如何使用 pthread_join 函數(shù)來等待一個線程結(jié)束。
#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], NULL, wait, &&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);
}
當(dāng)上述代碼編譯和執(zhí)行后,將產(chǎn)生以下的結(jié)果:
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.