多線程

2018-08-12 22:03 更新

多線程

多線程是多任務(wù)處理的一種特殊形式,而多任務(wù)處理是一種讓你的電腦能并發(fā)運(yùn)行兩個(gè)或兩個(gè)以上程序的特性。一般有兩種類(lèi)型的多任務(wù)處理:基于進(jìn)程的和基于線程的。

基于進(jìn)程的多任務(wù)處理是并發(fā)執(zhí)行的程序。基于線程的多任務(wù)處理是并發(fā)執(zhí)行的程序的一部分。

多線程程序包含了可以并發(fā)運(yùn)行的兩個(gè)或更多個(gè)程序部分。這樣程序中的每個(gè)部分稱(chēng)為一個(gè)線程,并且每個(gè)線程都定義了一個(gè)單獨(dú)的執(zhí)行路徑。

C++ 不包含對(duì)多線程應(yīng)用程序的任何嵌入式支持。相反,它完全依賴(lài)于操作系統(tǒng)來(lái)提供此項(xiàng)功能。

本教程假設(shè)您正在使用的是 Linux 操作系統(tǒng),我們將要使用 POSIX 編寫(xiě) C++ 多線程程序。 POSIX 線程,或稱(chēng) Pthreads,它提供了在許多類(lèi) Unix 的 POSIX 系統(tǒng)(如 FreeBSD,NetBSD,GNU/Linux,Mac OS X 和 Solaris)中可用的 API。

創(chuàng)建線程

我們使用下面的函數(shù)來(lái)創(chuàng)建一個(gè) POSIX 線程:

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

這里的 pthread_create 創(chuàng)建了一個(gè)新線程,并使其可執(zhí)行。這個(gè)函數(shù)可以在代碼中的任意位置調(diào)用任意次。

下面是詳細(xì)的參數(shù)說(shuō)明:

參數(shù) 描述
thread 新線程的不透明、唯一的標(biāo)識(shí)符,它由子函數(shù)返回。
attr 一個(gè)不透明的屬性對(duì)象,可用于設(shè)置線程屬性。你可以指定一個(gè)線程的屬性對(duì)象,默認(rèn)值為 NULL。
start_routine C++ 例程,線程一旦創(chuàng)建將會(huì)被執(zhí)行。
arg 一個(gè)傳遞給 start_routine 的參數(shù)。它必須傳遞一個(gè) void 類(lèi)型指針的引用。如果沒(méi)有參數(shù)傳遞,默認(rèn)值為 NULL。

一個(gè)進(jìn)程可創(chuàng)建的最大線程數(shù)是依賴(lài)實(shí)現(xiàn)決定的。線程一旦創(chuàng)建,它們之間是對(duì)等的,而且也有可能創(chuàng)建其它的線程。線程之間沒(méi)有隱含的層次或依賴(lài)關(guān)系。

終止線程

我們使用下面的函數(shù)來(lái)終止一個(gè) POSIX 線程:

    #include <pthread.h>
    pthread_exit (status)

此處的 pthread_exit 用于顯式的退出一個(gè)線程。通常在線程已完成了其工作,并且沒(méi)有存在的必要的時(shí)候,調(diào)用 pthread_exit()函數(shù)。

如果 main()在其創(chuàng)建的線程之前終止,并且使用了 pthread_exit() 來(lái)退出線程,那么其線程將會(huì)繼續(xù)執(zhí)行。否則,當(dāng) main() 終止后,這些線程將會(huì)自動(dòng)終止。

例子

下面簡(jiǎn)單的樣例代碼,用 pthread_create() 函數(shù)創(chuàng)建了 5 個(gè)線程。每個(gè)線程均打印 “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 庫(kù)編譯上面的程序,如下所示:

    $gcc test.cpp -lpthread

現(xiàn)在執(zhí)行上面的程序,將會(huì)產(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

傳遞參數(shù)給線程

下面的例子展示了如何通過(guò)一個(gè)結(jié)構(gòu)體傳遞多個(gè)參數(shù)。你可以在一個(gè)線程回調(diào)中傳遞任何數(shù)據(jù)類(lèi)型,這是因?yàn)樗赶?void 類(lèi)型。

下面的例子解釋了這一點(diǎn):

    #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í)行后,將會(huì)有以下的結(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

連接和分離線程

下面的兩個(gè)函數(shù),我們可以用它們來(lái)連接或分離線程:

    pthread_join (threadid, status) 
    pthread_detach (threadid) 

pthread_join()子例程會(huì)阻塞調(diào)用它的線程,一直等到其指定的 threadid 的線程結(jié)束為止。當(dāng)一個(gè)線程創(chuàng)建后,它的屬性決定了它是否是可連接的或可分離的。只有創(chuàng)建時(shí)屬性為可連接的線程才可以連接。如果創(chuàng)建的是一個(gè)可分離的線程,那么它永遠(yuǎn)不能連接。

下面的例子演示了如何使用 pthread_join 函數(shù)來(lái)等待一個(gè)線程結(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, &amp;&amp;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.
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)