一個進程中可以包含多個線程。線程中包含了表示進程執行環境必須的資訊,其中包括進程中標識線程的線程ID、一組寄存器值、棧、調度 優先順序和策略、訊號屏蔽字、errno變數以及線程私人資料。進程的所有資訊對該進程的所有線程都是共用的,包括可執行檔程式文本、程式的全域記憶體和堆記憶體、棧以及檔案描述符。
需要注意的是,進程ID是全域唯一的,但是線程ID只有在它所屬的進程環境中有效。
通過調用函數pthread_create來建立線程(更多內容:man 3 pthread_create):
1 #include <pthread.h>2 3 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);4 5 // Compile and link with -pthread
View Code
其中,參數arg作為線程開始函數start_routine的傳遞參數。若傳遞參數不止一個,則將這些參數放在一個結構體中,然後把這個結構的地址作為arg參數傳入。
注意,線程建立時並不能保證哪個線程會先運行:是新建立的線程還是調用線程。
若進程中任一線程調用exit,_Exit或_exit,那麼整個進程會終止。在不終止整個進程的情況下停止它的控制流程,單個線程可以通過以下三種方式退出:
- 線程從start_routine中返回,則傳回值就是線程的退出碼;
- 線程可以被同一進程中的其他線程利用函數pthread_cancel函數來取消;
- 線程在start_routine中調用pthread_exit。
同一進程中的其他線程可以通過函數pthread_join來擷取指定線程的退出碼(man 3 pthread_join)。若該函數第二個參數設定為NULL,則pthread_join函數將等待指定線程終止。在預設情況下,線程的之中狀態會儲存到對該線程調用pthread_join,如果線程已經處於分離狀態,線程的底層儲存資源可以線上程終止時立即被收回。當線程被分離時,並不能用pthread_join函數等待它的終止狀態。
同一進程中的其他線程可以調用函數pthread_cancel來請求取消同一進程中的其他線程。
函數pthread_detach可以用於使線程進入分離狀態。
例子(來自pthread_create的linux說明文檔):
1 #include <pthread.h> 2 #include <string.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <unistd.h> 6 #include <errno.h> 7 #include <ctype.h> 8 9 #define handle_error_en(en, msg) \ 10 do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) 11 12 #define handle_error(msg) \ 13 do { perror(msg); exit(EXIT_FAILURE); } while (0) 14 15 struct thread_info /* Used as argument to thread_start() */ 16 { 17 pthread_t thread_id; /* ID returned by pthread_create() */ 18 int thread_num; /* Application-defined thread # */ 19 char *argv_string; /* From command-line argument */ 20 }; 21 22 /* Thread start function: display address near top of our stack, 23 and return upper-cased copy of argv_string */ 24 25 static void * 26 thread_start(void *arg) 27 { 28 struct thread_info *tinfo = (struct thread_info *) arg; 29 char *uargv, *p; 30 31 printf("Thread %d: top of stack near %p; argv_string=%s\n", 32 tinfo->thread_num, &p, tinfo->argv_string); 33 34 uargv = strdup(tinfo->argv_string); 35 if (uargv == NULL) 36 handle_error("strdup"); 37 38 for (p = uargv; *p != '\0'; p++) 39 *p = toupper(*p); 40 41 return uargv; 42 } 43 44 int 45 main(int argc, char *argv[]) 46 { 47 int s, tnum, opt, num_threads; 48 struct thread_info *tinfo; 49 pthread_attr_t attr; 50 int stack_size; 51 void *res; 52 53 /* The "-s" option specifies a stack size for our threads */ 54 55 stack_size = -1; 56 while ((opt = getopt(argc, argv, "s:")) != -1) 57 { 58 switch (opt) 59 { 60 case 's': 61 stack_size = strtoul(optarg, NULL, 0); 62 break; 63 64 default: 65 fprintf(stderr, "Usage: %s [-s stack-size] arg...\n", 66 argv[0]); 67 exit(EXIT_FAILURE); 68 } 69 } 70 71 num_threads = argc - optind; 72 73 /* Initialize thread creation attributes */ 74 75 s = pthread_attr_init(&attr); 76 if (s != 0) 77 handle_error_en(s, "pthread_attr_init"); 78 79 if (stack_size > 0) 80 { 81 s = pthread_attr_setstacksize(&attr, stack_size); 82 if (s != 0) 83 handle_error_en(s, "pthread_attr_setstacksize"); 84 } 85 86 /* Allocate memory for pthread_create() arguments */ 87 88 tinfo = calloc(num_threads, sizeof(struct thread_info)); 89 if (tinfo == NULL) 90 handle_error("calloc"); 91 92 /* Create one thread for each command-line argument */ 93 94 for (tnum = 0; tnum < num_threads; tnum++) 95 { 96 tinfo[tnum].thread_num = tnum + 1; 97 tinfo[tnum].argv_string = argv[optind + tnum]; 98 99 /* The pthread_create() call stores the thread ID into100 corresponding element of tinfo[] */101 102 s = pthread_create(&tinfo[tnum].thread_id, &attr,103 &thread_start, &tinfo[tnum]);104 if (s != 0)105 handle_error_en(s, "pthread_create");106 }107 108 /* Destroy the thread attributes object, since it is no109 longer needed */110 111 s = pthread_attr_destroy(&attr);112 if (s != 0)113 handle_error_en(s, "pthread_attr_destroy");114 115 /* Now join with each thread, and display its returned value */116 117 for (tnum = 0; tnum < num_threads; tnum++)118 {119 s = pthread_join(tinfo[tnum].thread_id, &res);120 if (s != 0)121 handle_error_en(s, "pthread_join");122 123 printf("Joined with thread %d; returned value was %s\n",124 tinfo[tnum].thread_num, (char *) res);125 free(res); /* Free memory allocated by thread */126 }127 128 free(tinfo);129 exit(EXIT_SUCCESS);130 }
View Code
運行結果: