创建与终止线程
线程的管理常用的API有:
pthread_create(thread,attr,start_routine,arg)
pthread_exit(status)
pthread_cancel(thread)
pthread_attr_init(attr)
pthread_attr_destroy(attr)
创建线程:
-
一个main程序包含一个默认的主线程,这个主线程在程序开始运行的时候由系统创建。除此之外的所有其他线程必须由程序员显式的创建。
-
pthread_create 创建一个可执行的线程。每次调用创建一个线程,同时,你可以在任何位置调用该函数。
-
pthread_create 参数:
- thread:唯一标示一个新线程的用户不可见的标识符,由pthread_create产生
- attr:一个线程的不可见的属性对象,可以用来设置新建线程的属性。可以传进一个线程属性对象,类型为pthread_attr_t;或者传NULL来使用默认值。
- start_routine: 新线程创建好之后由新线程立即执行的子程序
- arg:传给 start_routine的一个参数。它必须为void类型的指针,当然没有参数或者使用默认可以传NULL。如果想传进多个参数,可以它们封装进一个结构体。
-
一个进程可以创建的线程数量的最大值在不同的系统内有不同的实现。
-
在Linux查询和设置你的系统的线程数量限制方法如下:
-
bash / ksh / sh tcsh / csh $ ulimit -a core file size (blocks, -c) 16 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 255956 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) unlimited cpu time (seconds, -t) unlimited max user processes (-u) 1024 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited $ ulimit -Hu 7168 $ ulimit -u 7168 $ ulimit -a core file size (blocks, -c) 16 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 255956 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) unlimited cpu time (seconds, -t) unlimited max user processes (-u) 7168 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
% limit cputime unlimited filesize unlimited datasize unlimited stacksize unlimited coredumpsize 16 kbytes memoryuse unlimited vmemoryuse unlimited descriptors 1024 memorylocked 64 kbytes maxproc 1024 % limit maxproc unlimited % limit cputime unlimited filesize unlimited datasize unlimited stacksize unlimited coredumpsize 16 kbytes memoryuse unlimited vmemoryuse unlimited descriptors 1024 memorylocked 64 kbytes maxproc 7168
-
一旦建立,线程之间是并行的,同时可以在线程内创建新的线程。线程之间没有继承或者依赖关系。
线程属性
-
默认情况下,一个线程创建之后包含一些默认属性。其中一些可以由传递进去的线程属性对象改变。
-
pthread_attr_init 和 pthread_attr_destroy 用来初始化和销毁一个线程属性对象
-
还有一些其他API可以用来查询或者设置线程属性对象中的特定的属性。线程的属性包括:
- 分离或可结合状态
- 调度继承
- 调度策略
- 调度参数
- 调度竞争范围
- 栈尺寸
- 栈地址
- 栈保护区大小
终止线程 pthread_exit():
-
线程在以下几种情况下会终止:
- 线程从其start_routine正常返回,其工作全部完成
- 线程调用了pthread_exit(),无论其工作是否完成
- 线程被其他线程通过调用pthread_cancel()取消
- 线程所在的进程调用了exec() 或者 exit()
- main()函数结束
-
pthread_exit()允许程序员指定一个可选的终止状态参数。这个可选的参数通常将返回线程“加入”终止线程。
- pthread_exit()不会关闭文件,任何在线程内打开的文件在线程通过调用pthread_exit()终止后仍继续保持打开状态。
线程的创建和终止示例代码
- 在这个简单的例子中将通过调用prhtread_ctreate()建立5个线程,每个线程输出“Hello World!”,然后调用pthread_exit()终止。这里是结果
-
1 #include <pthread.h> 2 #include <stdio.h> 3 #define NUM_THREADS 5 4 5 void *PrintHello(void *threadid) 6 { 7 long tid; 8 tid = (long)threadid; 9 printf("Hello World! It‘s me, thread #%ld!\n", tid); 10 pthread_exit(NULL); 11 } 12 13 int main (int argc, char *argv[]) 14 { 15 pthread_t threads[NUM_THREADS]; 16 int rc; 17 long t; 18 for(t=0; t<NUM_THREADS; t++){ 19 printf("In main: creating thread %ld\n", t); 20 rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t); 21 if (rc){ 22 printf("ERROR; return code from pthread_create() is %d\n", rc); 23 exit(-1); 24 } 25 } 26 27 /* Last thing that main() should do */ 28 pthread_exit(NULL); 29 }
向线程传递参数
-
pthread_create()允许传递一个参数到线程启动时调用的函数即所谓的start_routine。在需要传多个参数的时候,可以通过创建一个封装很多参数的结构体,然后将指向该结构体的指针传给 pthread_create()就可以了。
-
所有的参数必须以指针形式传递,同时转为类型为void。
-
线程传递参数的示例代码:这里是结果
-
1 /****************************************************************************** 2 * FILE: hello_arg1.c 3 * DESCRIPTION: 4 * A "hello world" Pthreads program which demonstrates one safe way 5 * to pass arguments to threads during thread creation. 6 ******************************************************************************/ 7 #include <pthread.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #define NUM_THREADS 8 11 12 char *messages[NUM_THREADS]; 13 14 void *PrintHello(void *threadid) 15 { 16 int *id_ptr, taskid; 17 18 sleep(1); 19 id_ptr = (int *) threadid; 20 taskid = *id_ptr; 21 printf("Thread %d: %s\n", taskid, messages[taskid]); 22 pthread_exit(NULL); 23 } 24 25 int main(int argc, char *argv[]) 26 { 27 pthread_t threads[NUM_THREADS]; 28 int *taskids[NUM_THREADS]; 29 int rc, t; 30 31 messages[0] = "English: Hello World!"; 32 messages[1] = "French: Bonjour, le monde!"; 33 messages[2] = "Spanish: Hola al mundo"; 34 messages[3] = "Klingon: Nuq neH!"; 35 messages[4] = "German: Guten Tag, Welt!"; 36 messages[5] = "Russian: Zdravstvytye, mir!"; 37 messages[6] = "Japan: Sekai e konnichiwa!"; 38 messages[7] = "Latin: Orbis, te saluto!"; 39 40 for(t=0;t<NUM_THREADS;t++) { 41 taskids[t] = (int *) malloc(sizeof(int)); 42 *taskids[t] = t; 43 printf("Creating thread %d\n", t); 44 rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]); 45 if (rc) { 46 printf("ERROR; return code from pthread_create() is %d\n", rc); 47 exit(-1); 48 } 49 } 50 51 pthread_exit(NULL); 52 }
传递多个参数的例子,请看这里
Joining and Detaching 线程
pthread_join(threadid,status)
pthread_detach(threadid)
pthread_attr_setdetachstate(attr,detachstate)
pthread_atr_getdetachstate(attr,detachstate)
-
Joining:
-
"Joining"是线程间同步的一种方式。
-
pthread_join()会阻塞调用的线程直至制定的threadid线程终止
-
如果在指定的目标线程中调用pthread_exit(),程序员可以获得目标线程的终止返回状态。
-
线程一个创建,其中的一个属性就被制定为joinable或者detached。而且只有joinable的线程才可以使用这种同步方式。
-
显式的创建一个线程为joinable或者detached,可以在pthread_create()中使用属性参数,步骤如下: 1) 声明一个线程属性变量,类型为pthread_attr_t 2) 使用pthread_attr_init()初始化属性变量 3) 使用pthread_attr_setdetachstate()设置属性分离状态 4) 程序结束时,使用pthread_attr_destroy()释放属性对象使用的资源
-
还有两种同步方法,互斥锁和条件变量,将在以后的blog中讨论
-
-
Detaching
-
pthread_detach()可以显式的detach一个线程即便它创建的时候是joinable。
-
没有相反的API
-
-
Pthread Joining示例代码如下:这里是结果
1 /***************************************************************************** 2 * FILE: join.c 3 * DESCRIPTION: 4 * This example demonstrates how to "wait" for thread completions by using 5 * the Pthread join routine. Threads are explicitly created in a joinable 6 * state for portability reasons. Use of the pthread_exit status argument is 7 * also shown. Compare to detached.c 8 ******************************************************************************/ 9 #include <pthread.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #define NUM_THREADS 4 13 14 void *BusyWork(void *t) 15 { 16 int i; 17 long tid; 18 double result=0.0; 19 tid = (long)t; 20 printf("Thread %ld starting...\n",tid); 21 for (i=0; i<1000000; i++) 22 { 23 result = result + sin(i) * tan(i); 24 } 25 printf("Thread %ld done. Result = %e\n",tid, result); 26 pthread_exit((void*) t); 27 } 28 29 int main (int argc, char *argv[]) 30 { 31 pthread_t thread[NUM_THREADS]; 32 pthread_attr_t attr; 33 int rc; 34 long t; 35 void *status; 36 37 /* Initialize and set thread detached attribute */ 38 pthread_attr_init(&attr); 39 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 40 41 for(t=0; t<NUM_THREADS; t++) { 42 printf("Main: creating thread %ld\n", t); 43 rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t); 44 if (rc) { 45 printf("ERROR; return code from pthread_create() is %d\n", rc); 46 exit(-1); 47 } 48 } 49 50 /* Free attribute and wait for the other threads */ 51 pthread_attr_destroy(&attr); 52 for(t=0; t<NUM_THREADS; t++) { 53 rc = pthread_join(thread[t], &status); 54 if (rc) { 55 printf("ERROR; return code from pthread_join() is %d\n", rc); 56 exit(-1); 57 } 58 printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status); 59 } 60 61 printf("Main: program completed. Exiting.\n"); 62 pthread_exit(NULL); 63 }