多線程,它是讓電腦更好用的東西,也是程式員最容易犯錯的東西—-小話c語言(13)

來源:互聯網
上載者:User

[Mac-10.7.1  Lion  Intel-based  x64  gcc4.2.1]

Q:  c標準中包含線程操作嗎?

A: 沒有。

Q: 給個mac下線程操作的例子吧。

A: 建立線程的函數可以實用pthread_create, 原型如下:

int  pthread_create(pthread_t *restrict thread,         const pthread_attr_t *restrict attr,          void *(*start_routine)(void *),         void *restrict arg);

thread是儲存成功建立線程結構資訊; attr表示線程的相關屬性,start_routine表示線程執行的函數, arg表示線程執行的使用的參數。

範例程式碼(儲存為testForC.c):

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)      printf(#str" is %s\n", (str));void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);    }    return NULL;}int main(){    pthread_t thread;    int ret;    ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        return 0;}

運行:

可以看到,程式運行後然後很快就結束了,且沒有任何輸出。這是因為主線程過快結束導致結束了剛剛建立的子線程。

Q:如何讓主線程不理解結束呢?

A: 可以讓主線程進入等待狀態,加入while(1)迴圈讓主線程一直等待。

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);    }    return NULL;}int main(){    pthread_t thread;    int ret;    ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        FOR_EVER();    return 0;}

運行結果:

上面是在子線程輸出字串的過程中截取的,子線程會一直運行下去,知道自己的迴圈退出。

Q: 子線程啟動並執行這麼快,讓它慢點行不?

A: 在子線程的while迴圈中加個延遲1秒的函數,如下:

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);        sleep(1);       // sleep for 1 second    }    return NULL;}int main(){    pthread_t thread;    int ret;    ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        FOR_EVER();    return 0;}

運行結果:

從實際運行可以看出,子線程每列印一行會延遲一下。

Q: 主線程如何在規定的時間內幹掉子線程?

A: 主線程可以啟動定時器,在指定時間內幹掉子線程。

int  setitimer(int which,  const struct itimerval *restrict value,  struct itimerval *restrict ovalue);

參數which表示定時器類型,value表示定時器時間資訊,ovalue可以設定為NULL.

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }pthread_t   thread;int         should_loop = 1;void    kill_son_thread(int arg){    printf("now it will kill son thread...\n");    pthread_cancel(thread);    should_loop = 0;}void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);        sleep(1);       // sleep for 1 second    }    return NULL;}int main(){    int ret;    struct itimerval timer;        ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret !=  0)    {        perror("pthread_create error");        return -1;    }        // set the timer    timer.it_value.tv_sec = 5;    timer.it_value.tv_usec = 0;    timer.it_interval.tv_sec = 5;    timer.it_interval.tv_usec = 0;        signal(SIGALRM, kill_son_thread);       // register a signal for timer action    setitimer(ITIMER_REAL, &timer, NULL);   // start the timer    while(should_loop)        ;    return 0;}

運行結果:


可以看到,主線程大約5秒後幹掉了子線程,然後結束了。

Q: pthread_exit不也可以退出線程嗎?

A: 是的。不用定時器,子線程5秒後自動結束,代碼如下:

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }pthread_t   thread;int         should_loop = 1;void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);        sleep(1);       // sleep for 1 second        if(i == 6)        {            should_loop = 0;            printf("[Son thread]: end...\n");            pthread_exit(NULL);        }    }    return NULL;}int main(){    int ret;        ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        while(should_loop)        ;    printf("[Main thread]: end...\n");    return 0;}

運行結果:

Q: 還有個函數,pthread_join的作用是什嗎?

A: 它的作用是等待指定線程執行結束。它實現了線程之間的同步。

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }pthread_t   thread;int         should_loop = 1;void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        printf("thread: loop %d\n", i++);        sleep(1);       // sleep for 1 second        if(i == 6)        {            should_loop = 0;            pthread_exit(NULL);        }    }    return NULL;}int main(){    int ret;        ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        pthread_join(thread, NULL);     // wait for the son thread's end    printf("[Son thread]: end...\n");    while(should_loop)        ;    printf("[Main thread]: end...\n");    return 0;}

運行結果:

Q: 上面的情形,主線程需要等待子線程結束,如果主線程不必等待子線程結束,子線程為主線程提供必要的資料,二者同步運行,如何處理?

A: 那麼,可以使用互斥體、訊號量等。

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }pthread_t   thread;int         should_loop = 1;pthread_mutex_t mutex;int         data[3];void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        pthread_mutex_lock(&mutex);        data[0] = i;        data[1] = i + 1;        data[2] = i + 2;        ++i;        sleep(1);        pthread_mutex_unlock(&mutex);          }    return NULL;}int main(){    int ret;    // create and init a mutex    pthread_mutex_init(&mutex, NULL);        ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret != 0)    {        perror("pthread_create error");        return -1;    }        while(1)    {        pthread_mutex_lock(&mutex);        if(data[0] > 3)        {            pthread_mutex_unlock(&mutex);            break;        }        printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]);        pthread_mutex_unlock(&mutex);        sleep(1);         // avoid the main thread running too fast, thanks  wufangna !    }    pthread_mutex_destroy(&mutex);    printf("[Main thread]: end...\n");        return 0;}

上面的代碼,主線程從全域資料data中讀取資料,子線程大約每1秒更新下data中的資料,當data[0]的值大於3的時候主線程退出。

運行結果:

Q: 還有種類型pthread_cond_t,它和pthread_mutex_t有什麼區別?

A: 前者是在某種情況下設定的"互斥體", 後者可以當成無條件的互斥體;例子如下,

#include <stdio.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <sys/time.h>#include <sys/signal.h>#define PRINT_D(intValue)       printf(#intValue" is %d\n", (intValue));#define PRINT_STR(str)          printf(#str" is %s\n", (str));#define FOR_EVER()              { while(1) ; }pthread_t   thread;int         should_loop = 1;pthread_mutex_t mutex;int         data[3];pthread_cond_t  cond;void    *thread_one_func(void *args){    int i = 1;    while (i > 0)    {        pthread_mutex_lock(&mutex);        data[0] = i;        data[1] = i + 1;        data[2] = i + 2;        if(data[0] % 2 == 0)            pthread_cond_signal(&cond);        ++i;        sleep(1);        pthread_mutex_unlock(&mutex);          }    return NULL;}int main(){    int ret;    // create and init a mutex    pthread_mutex_init(&mutex, NULL);    pthread_cond_init(&cond, NULL);        ret = pthread_create(&thread, NULL, thread_one_func, NULL);    if(ret  !=  0)    {        perror("pthread_create error");        return -1;    }        while(1)    {        pthread_mutex_lock(&mutex);        if(data[0] > 6)        {            pthread_mutex_unlock(&mutex);            break;        }        pthread_cond_wait(&cond, &mutex);                    printf("[Main thread]: %d %d %d\n", data[0], data[1], data[2]);        pthread_mutex_unlock(&mutex);    }        pthread_cond_destroy(&cond);    pthread_mutex_destroy(&mutex);    printf("[Main thread]: end...\n");        return 0;}

上面的代碼,主線程當發現data[0]大於6時就退出;小於6的時候,等待cond的狀態變化;子線程會更新data數組中的數值,且當data[0]是偶數的時候就啟用等待cond的線程(主線程),二者實現同步和互斥。

運行效果:

對於同步互斥,semaphore也可以實現; sem_open, sem_wait等等是操作它的函數,這裡不再一一介紹。

xichen

2012-5-19 15:46:26

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.