一个进程中可以包含多个线程。线程中包含了表示进程执行环境必须的信息,其中包括进程中标识线程的线程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
其中,参数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 into 100 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 no 109 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 }
运行结果: