多線程OR多進程

來源:互聯網
上載者:User

最近在看   posix多線程程式設計   這是書上前面的一個鬧鐘的小程式,有幾個版本做了比較

 

 

1. 基本的同步版本

  1. /*

  2. * alarm.c

  3. *

  4. * Simple synchronous alarm program. This is used as a

  5. * reference for progressive examples of asynchronous

  6. * alarm programs.

  7. */  

  8. #include "errors.h"  

  9.  

  10. int main (int argc, char **argv)  

  11. {  

  12.    int seconds;  

  13.    char line[128];  

  14.    char message[64];  

  15.  

  16.    while (1)  

  17.    {  

  18.        printf("Alarm> ");  

  19.        if (fgets(line, sizeof(line), stdin) == NULL)  

  20.            exit(0);  

  21.        if (strlen(line) <= 1)  

  22.            continue;  

  23.  

  24.        /**

  25.         Parse input line into seconds (%d) and a message (%64[^\n]),

  26.         consisting of up to 64 characters separated from the seconds

  27.         by whitespace.

  28.        */  

  29.        if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2)  

  30.        {  

  31.            fprintf(stderr, "Bad command\n");  

  32.        }  

  33.        else  

  34.        {  

  35.            sleep(seconds);  

  36.            printf("(%d) %s\n", seconds, message);  

  37.        }  

  38.    }  

  39. }  

特點:同步實現非同步,鬧鐘請求後,程式睡眠等待鬧鐘時間到;

問題:用同步方式來實現非同步,一次只能處理一個鬧鐘請求;即程式睡眠時間到後才能進行下一次鬧鐘請求;

 

運行結果。

  1. # ./alarm  

  2. Alarm> 5  

  3. Bad command  

  4. Alarm> 5 this is a test with 5 seconds  

  5. (5) this is a test with 5 seconds      //等待5秒並列印該訊息  

  6. Alarm> 10 the seconds with 10 seconds  

  7. (10) the seconds with 10 seconds       //等待10秒並列印該訊息  

  8. Alarm> 

 

 

2. 多進程版本

  1. /*

  2. * alarm_fork.c

  3. *

  4. * This version of alarm.c uses fork to create a new process to

  5. * wait for each alarm to expire.

  6. */  

  7. #include <sys/types.h>  

  8. #include <wait.h>  

  9. #include "errors.h"  

  10.  

  11. int main(int argc, char **argv)  

  12. {  

  13.    int status;  

  14.    char line[128];  

  15.    int seconds;  

  16.    pid_t pid;  

  17.    char message[64];  

  18.  

  19.    while (1)  

  20.    {  

  21.        printf ("Alarm> ");  

  22.        if (fgets(line, sizeof(line), stdin) == NULL) exit(0);  

  23.        if (strlen(line) <= 1) continue;  

  24.  

  25.        /**

  26.         Parse input line into seconds (%d) and a message (%64[^\n]),

  27.         consisting of up to 64 characters separated from the seconds

  28.         by whitespace.

  29.        */  

  30.        if (sscanf(line, "%d %64[^\n]", &seconds, message) < 2)  

  31.        {  

  32.            fprintf(stderr, "Bad command\n");  

  33.        }  

  34.        else  

  35.        {  

  36.            pid = fork();  

  37.            if (pid == (pid_t)-1)  

  38.                errno_abort("Fork");  

  39.            if (pid == (pid_t)0)  

  40.            {  

  41.                /*

  42.                 * If we're in the child, wait and then print a message

  43.                 */  

  44.                sleep(seconds);  

  45.                printf("pid = %d, (%d) %s\n", pid, seconds, message);  

  46.                exit(0);  

  47.            }  

  48.            else  

  49.            {  

  50.                /*

  51.                 * In the parent, call waitpid() to collect any children that

  52.                 * have already terminated.

  53.                 */  

  54.                do  

  55.                { 

  56.                    pid = waitpid((pid_t)-1, NULL, WNOHANG);  

  57.                    if (pid == (pid_t)-1)  

  58.                        errno_abort("Wait for child");  

  59.                } while (pid != (pid_t)0);  

  60.            }  

  61.         }  

  62. }  

特點:在子進程中非同步地調用sleep函數,而父進程繼續運行;

問題:對每次鬧鐘請求,使用fork建立子進程,程式開銷過大;

waitpid()函數

  • WNOHANG:父進程不必掛起等待子進程的結束;

  • 如果有子進程終止,該函數回收該子進程的資源;

  • 如果沒有子進程終止,該函數立即返回pid=0;父進程繼續回收終止的子進程直到沒有子進程終止;

  • 在每個命令之後迴圈調用waitpid,來回收所有結束的子進程;

     

運行結果。

  1. Alarm> 3 test 1                        //輸入命令  

  2. Alarm> 5 test 2                        //輸入命令  

  3. Alarm> (3) test 1                      //等待3秒並列印該訊息  

  4. 10 test 3                              //輸入命令  

  5. Alarm> (5) test 2                      //等待5秒並列印該訊息  

  6.  

  7. Alarm> (10) test 3                     //等待10秒並列印該訊息  

  8.  

  9. Alarm>  

 

 

 

3.多線程版本

 

 
  1. /*

  2. * alarm_fork.c

  3. *

  4. * This version of alarm.c uses pthread_create to create a

  5. * separate thread to wait for each alarm to expire.

  6. */  

  7. #include <pthread.h>  

  8. #include "errors.h"  

  9.  

  10. typedef struct alarm_tag {  

  11.    int         seconds;  

  12.    char       message[64];  

  13. } alarm_t;  

  14.  

  15. void *alarm_thread (void *arg)  

  16. {  

  17.    alarm_t *alarm = (alarm_t*)arg;  

  18.    int status;  

  19.  

  20.    status = pthread_detach (pthread_self ());  

  21.    if (status != 0)  

  22.        err_abort (status, "Detach thread");  

  23.    sleep (alarm->seconds);  

  24.    printf ("(%d) %s\n", alarm->seconds, alarm->message);  

  25.    free (alarm);  

  26.    return NULL;  

  27. }  

  28.  

  29. int main (int argc, char *argv[])  

  30. {  

  31.    int status;  

  32.    char line[128];  

  33.    alarm_t *alarm;  

  34.    pthread_t thread;  

  35.  

  36.    while (1) {  

  37.        printf ("Alarm> ");  

  38.        if (fgets (line, sizeof (line), stdin) == NULL) exit (0);  

  39.        if (strlen (line) <= 1) continue;  

  40.        alarm = (alarm_t*)malloc (sizeof (alarm_t));  

  41.        if (alarm == NULL)  

  42.            errno_abort ("Allocate alarm");  

  43.  

  44.        /*

  45.         * Parse input line into seconds (%d) and a message

  46.         * (%64[^\n]), consisting of up to 64 characters

  47.         * separated from the seconds by whitespace.

  48.         */  

  49.        if (sscanf (line, "%d %64[^\n]", &alarm->seconds, alarm->message) < 2) {  

  50.            fprintf (stderr, "Bad command\n");  

  51.            free (alarm);  

  52.        } else {  

  53.            status = pthread_create(&thread, NULL, alarm_thread, alarm);  

  54.            if (status != 0)  

  55.                err_abort (status, "Create alarm thread");  

  56.        }  

  57.    }  

  58. }  

特點:在該例子中,alarm線程調用pthread_detach()函數來分離自己,通知pthreads不必關心它的終止時間和退出狀態;因此不需要等待線程結束,除非希望獲得它的傳回值。alarm線程的資源在它終止後立即回收。

一般地,pthreads會儲存線程的資源以使其他線程瞭解它已經終止並獲得其最終結果。在本例中,alarm線程負責自己分離自己。

該版本用到以下函數:

  • pthread_create():建立線程,運行代碼由第三個參數指定,運行代碼需要的參數由第四個參數傳入;返回線程標誌符;

  • Pthread_detach():當線程終止時允許pthreads立即回收線程資源;

  • pthread_exit():終止調用線程;

運行結果。

 
  1. # ./alarm_thread  

  2. Alarm> 5 atest  

  3. Alarm> 10 btest  

  4. Alarm> (5) atest  

  5.  

  6. Alarm> 15 ctest  

  7. Alarm> (10) btest  

  8. Alarm>  (15) ctest  

  9.  

  10. Alarm>  

4. 小結

多進程版本

  • 每個鬧鐘有一個從主進程拷貝的獨立地址空間;

  • 主進程調用waitpid來告訴系統釋放其建立的子進程資源;

多線程版本

  • 所有線程共用同一個地址空間;

  • 不需要等待線程結束,除非希望獲得它的傳回值;

  • 線程間傳遞訊息更快

    • 不需要映射共用記憶體;

    • 不需要通過管道讀寫;

    • 不需要擔心進程間傳送的地址指標是否一致;

  • 線程間共用一切:一個線程內有效地址指標在所有線程內同樣有效;

多線程編程優點

  • 在多處理器系統中開發程式的並行性(僅並行性需要特殊硬體支援);

  • 在等待慢速外設I/O操作結束的同時,程式可以執行其他計算,為程式的並發提供更有效、更自然的開發方式;

  • 一種模組化編程模型,能清晰地表達程式中獨立事件間的相互關係;

多線程編程缺點

  • 計算負荷,如線程間同步需要的時間代價;

  • 需要設立較好的編程規則,如要避免死結、競爭和優先順序倒置等;

  • 更難以調試;

何種應用適合使用多線程?

  • 計算密集型應用,為了能在多處理器系統上運行,將這些計算分解到多個線程中實現;

  • IO密集型應用,為提高效能,將IO操作重疊;如分布式伺服器;

     

    我在ubuntu 10.10進行調試,用GCC編譯時間出現如下的報錯資訊。

    1. 

     fatal error: errors.h: No such file or directory

         然後我將errors.h換成error.h,這行代碼就沒有報錯,但是接下來就出現了這個問題

         undefined reference to `error_abort'

         undefined reference to `errno_abort'

         undefined reference to `err_abort'

         這個問題一直沒得到解決,不知道是這本書太舊而現在linux版本太高不相容的原因還是怎麼的,在網上查也一直沒查到原因,最後只能將其中的錯誤處理機制全部屏蔽掉,      如果哪位大牛知道解決方案的話,請不吝賜教。

        

          2.

           undefined reference to `pthread_detach'
           undefined reference to `pthread_create'

 

           這是由於pthread 庫不是 Linux 系統預設的庫,串連時需要使用靜態庫 libpthread.a,所以在使用pthread_create()建立線程時,需要連結該庫。
           問題解決:
           在編譯中要加 -lpthread參數
           gcc alarm_thread.c -o alarm_thread -lpthread

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.