標籤:pthread 線程
如何建立線程
Linux下一般使用POSIX線程庫,也叫pthread。編寫線程函數需要注意的是線程函數的傳回型別必須是void*;程式編譯的時候記得要連結上pthread庫,方法:-lpthread
簡單的線程程式
下面是簡單的線程程式,主程式裡建立了2個線程,分別列印不同的資訊。每個線程用pthread_create函數來建立。每個線程運行完程式之後,必須使用pthread_join函數來等待線程結束,也就是回收線程。一旦兩個線程都退出後,主程式就會退出。
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <pthread.h>void error(char *msg){ fprintf(stderr, "%s : %s\n", msg, strerror(errno) ); exit(1);}void* hello(void *a){ int i = 0; for(i = 0; i < 5; i++) { sleep(1); puts("hello linux!"); } return NULL;}void* goodbye(void *a){ int i = 0; for(i = 0; i < 5; i++) { sleep(1); puts("goodbye linux!"); } return NULL;}int main(int argc, char const *argv[]){ pthread_t t0; pthread_t t1; if(pthread_create(&t0, NULL, hello, NULL) == -1) error("cant creat pthread t0"); if(pthread_create(&t1,NULL, goodbye, NULL) == -1) error("cant creat pthread t1"); void* result; if(pthread_join(t0, &result) == -1) error("cant join pthread t0"); if(pthread_join(t1, &result) == -1) error("cant join pthread t1"); return 0;}
如果編譯器沒有添加-lpthread,就會出現下面的錯誤
[email protected]:~/test_code# gcc -Wall pthread.c -o pthread/tmp/cc5KEYbr.o:在函數‘main’中:pthread.c:(.text+0xec):對‘pthread_create’未定義的引用pthread.c:(.text+0x116):對‘pthread_create’未定義的引用pthread.c:(.text+0x138):對‘pthread_join’未定義的引用pthread.c:(.text+0x15a):對‘pthread_join’未定義的引用collect2: error: ld returned 1 exit status
成功編譯後,結果如下:
root@zengwh:~/test_code# gcc -Wall pthread.c -lpthread -o pthreadroot@zengwh:~/test_code# ./pthread goodbye linux!hello linux!goodbye linux!hello linux!goodbye linux!hello linux!hello linux!goodbye linux!hello linux!goodbye linux!
多個線程訪問共用資料
下面的程式,同時建立10個線程,每個線程公用一個函數,都是將全域變數number 減1000,等所有線程結束之後,再列印出變數的值,看是否等於0.
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <pthread.h>int number = 10000;void error(char *msg){ fprintf(stderr, "%s : %s\n", msg, strerror(errno) ); exit(1);}void* func(void *a){ int i = 0; for (i = 0; i < 1000; ++i) { number -= 1; } return NULL;}int main(int argc, char const *argv[]){ pthread_t thread[10]; int j = 0; printf("begining: the number is : %d\n", number ); for (j = 0; j < 10; ++j) { if (pthread_create(&thread[j], NULL, func, NULL) == -1) error("cant creat pthread t0"); } void* result; for (j = 0; j < 10; ++j) { if (pthread_join(thread[j], &result) == -1) error("cant creat pthread t0"); } printf("finally: the number is : %d\n", number ); return 0;}
程式運行結果如下:
[email protected]:~/test_code# ./pthread begining: the number is : 10000finally: the number is : 882[email protected]:~/test_code# ./pthread begining: the number is : 10000finally: the number is : 801[email protected]:~/test_code# ./pthread begining: the number is : 10000finally: the number is : 501[email protected]:~/test_code# ./pthread begining: the number is : 10000finally: the number is : 634[email protected]:~/test_code# ./pthread begining: the number is : 10000finally: the number is : 887
每次啟動並執行結果都不一樣。線程最大的優點在於可以同時運行多個不同任務,並訪問相同的資料,但訪問相同的資料也成為了線程的缺點。上面程式的結果就是線程撞車,結果是不可預測的。
建立互斥鎖
為了讓多個線程可以訪問共用資料且不會發生撞車,一種簡單辦法就是建立互斥鎖。
pthread_mutex_t a_lock = PTHREAD_MUTEX_INITIALIZER;
互斥鎖必須是一個全域變數,這樣才能對所有有可能發生撞車的線程可見。pthread_mutex_lock()函數只允許一個線程運行,其他線程處於等待。然後調用pthread_mutex_unlock()函數解鎖,其他線程可以進入。
pthread_mutex_lock(&a_lock);/*需要訪問的共用資料*/pthread_mutex_unlock(&a_lock);
增加鎖後的程式
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <errno.h>#include <pthread.h>int number = 10000;pthread_mutex_t number_lock = PTHREAD_MUTEX_INITIALIZER; void error(char *msg){ fprintf(stderr, "%s : %s\n", msg, strerror(errno) ); exit(1);}void* func(void *a){ int i = 0; pthread_mutex_lock(&number_lock); for (i = 0; i < 1000; ++i) { number -= 1; } pthread_mutex_unlock(&number_lock); printf("the number is : %d\n", number ); return NULL;}int main(int argc, char const *argv[]){ pthread_t thread[10]; int j = 0; printf("begining: the number is : %d\n", number ); for (j = 0; j < 10; ++j) { if (pthread_create(&thread[j], NULL, func, NULL) == -1) error("cant creat pthread t0"); } void* result; for (j = 0; j < 10; ++j) { if (pthread_join(thread[j], &result) == -1) error("cant creat pthread t0"); } printf("finally: the number is : %d\n", number ); return 0;}
需要注意的是
- 要控制碼中鎖的數量,不然會使程式變得很慢;
- 減少線程需要訪問的共用資料的數量,程式會更高效地進行
初試Linux下的線程編程