linux多线程编程.doc_第1页
linux多线程编程.doc_第2页
linux多线程编程.doc_第3页
linux多线程编程.doc_第4页
linux多线程编程.doc_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1.创建缺省线程22.终止线程23. 等待线程终止2pthread_exit和pthread_join进一步说明:34.分离线程75.获取线程标识符86.比较线程ID87. 一次性初始化88. 设置线程的调度策略和优先级99. 获取线程的优先级1110.取消线程12取消线程,是否会释放线程的所有资源?例子:14设置取消类型1611.初始化属性1712.设置分离状态1813.设置范围1814. 设置继承的调度策略1816. 设置调度参数1917.初始化互斥锁2118.销毁互斥锁2119.锁定互斥锁2220.解除锁定互斥锁2321. 互斥锁的类型:2322. 初始化互斥锁属性对象2323. 销毁互斥锁属性对象2324.设置互斥锁类型的属性24互斥锁动态初始化和静态初始化区别:26销毁互斥锁:事实上没做任何销毁操作,如下:27非递归类型的互斥锁解锁和加锁操作:2729.初始化条件变量2730.基于条件变量阻塞2731.解除阻塞一个线程2831.解除阻塞所有线程2933. 在指定的时间之前阻塞3032.唤醒丢失问题3133. 计数信号量概述3134. 初始化信号3135. 增加信号3136. 基于信号计数进行阻塞3237.多线程链表添加删除例子(使用条件变量实现互斥):3238.为线程特定数据创建键3439. 删除线程特定数据键3540.设置线程特定数据3541. 获取线程特定数据35读写锁属性初始化:36销毁读写锁属性对象:36设置读写锁共享属性:37初始化读写锁:37销毁读写锁:37读写锁总结:39获得写锁:39获得读锁:401.创建缺省线程int pthread_create(pthread_t *tid, cons、劈劈啪啪劈劈啪啪破婆婆t pthread_attr_t *tattr,void*(*start_routine)(void *), void *arg);参数:当pthread_create() 成功时,所创建线程的ID 被存储在由tid 指向的位置中。第二个参数用于设置线程属性,如果不需要特殊的属性,可以简单的设置该参数为NULL,最后两个参数告诉线程将要启动执行的函数和传递给该函数的参数。返回值:调用成功完成后返回0,其他的值都表示出现错误。如果检测到以下任一情况,pthread_create() 将失败并返回相应的值。EAGAIN 超出了系统限制,如创建的线程太多。EPERM 调用者没有适当的权限设置所需的参数或安排调度策略EINVAL 描述: tattr 的值无效。(设置的属性有问题)默认属性:绑定,非分离,继承创建者线程中定义的调度策略。2.终止线程void pthread_exit(void *status);本函数可用来终止调用线程。将释放调用线程所有特定数据绑定。如果调用线程尚未分离,则线程ID 和status 指定的退出状态将保持不变,直到应用程序调用pthread_join() 以等待该线程。否则,将忽略status。线程ID 可以立即回收。有一个重要的特殊情况,即当初始线程(即调用main() 的线程)从main() 调用返回时或调用exit() 时,整个进程及其所有的线程将终止。因此,一定要确保初始线程不会从main()过早地返回,在其它线程调用exit()也会终止整个进程。请注意,如果主线程仅仅调用了pthread_exit,则仅主线程本身终止。进程及进程内的其他线程将继续存在。所有线程都已终止时,进程也将终止。3. 等待线程终止int pthread_join(thread_t tid, void *status);参数:参数tid指定要等待的线程ID,指定的线程必须位于当前的进程中,而且不得是分离线程。当参数status 不是NULL 时,status 指向某个位置,在pthread_join() 成功返回时,将该位置设置为已终止线程的退出状态。返回值:调用成功完成后,pthread_join() 将返回零。其他任何返回值都表示出现了错误。如果检测到以下任一情况,pthread_join() 将失败并返回相应的值。ESRCH 描述: 没有找到与给定的线程ID 相对应的线程。EDEADLK 描述: 将出现死锁,如一个线程等待其本身,或者线程A和线程B 互相等待。EINVAL 描述: 与给定的线程ID 相对应的线程是分离线程。说明:如果多个线程等待同一个线程终止,则所有等待线程将一直等到目标线程终止。然后,一个等待线程成功返回。其余的等待线程将失败并返回ESRCH 错误。pthread_join() 仅适用于非分离的目标线程。如果没有必要等待特定线程终止之后才进行其他处理,则应当将该线程分离。pthread_exit和pthread_join进一步说明:(一下主线程是main线程)1.线程自己运行结束,或者调用pthread_exit()结束,线程都会释放自己独有的空间资源。2.如果线程是非分离的,线程会保留线程id号,直到其他线程通过joining这个线程确认其已死亡。join 的结果是joining 线程得到已终止线程的退出状态,已终止的线程将消失。3.如果线程是分离的,不需要使用pthread_exit(),线程自己运行结束,就会释放所有资源(包括线程id号)。4.子线程最终一定要使用pthread_join()或者设置为分离状态来结束线程,否则线程的资源不会被完全释放。(使用取消线程功能也不能完全释放)5.主线程运行pthread_exit(),会结束主线程,但不会结束子线程。6.主线程结束,则整个程序结束,所以主线程最好要使用join等待子线程运行结束。使用join一个线程可以等待多个线程结束。7.使用join的线程将会阻塞,直到被join的线程结束,join函数返回,但是它对被join的线程运行没有影响。8.如果子线程使用exit()则可以结束整个进程例子: 1 #include 2 #include 3 #include 4 #include 5 void * start_routine(void *arg) 6 7 char * a; 8 printf(thread runing,%sn, (char *)arg); 9 a = malloc(sizeof(char)*6); 10 memset(a, a, 5); 11 a5 = 0; 12 pthread_exit(void *)a); 13 14 int main(int argc, char *argv) 15 16 pthread_t tid; 17 char c4, *d; 18 memset(c, c, 3); 19 c3 = 0; 20 pthread_create(&tid, NULL, start_routine, (void *)c); 21 printf(pthread id :%un, tid); 22 pthread_join(tid, (void *)&d); 23 printf(main: %sn, d); 24 free(d); 25 return 0; 26 运行结果:pthread id :3077950352thread runing,cccmain: aaaaa 非分离线程未使用join函数例子: 1 #include 2 #include 3 #include 4 #include 5 #include 6 void *consumer(void *p) 7 8 static a = 0; 9 a+; 10 printf(%u),%dn, (unsigned)pthread_self(), a); 11 pthread_exit(NULL); 12 13 int main(int argc, char *argv) 14 15 pthread_t t1, t2, t3; 16 int ret; 17 do 18 ret = pthread_create(&t1, NULL, consumer, NULL); 19 if(ret != 0) 20 21 printf(create failed,%dn, ret); 22 exit(1); 23 24 while(1); 25 sleep(1); 26 return 0; 27 运行结果:创建350个左右的线程后,就不能再创建线程,已创建的线程线程号都不同。(33799056),362(25406352),363(17013648),364(8620944),365create failed,12如果主函数加上pthread_join(t1, NULL);才可以一直创建线程,如下,13 int main(int argc, char *argv) 14 15 pthread_t t1, t2, t3; 16 int ret; 17 do 18 ret = pthread_create(&t1, NULL, consumer, NULL); 19 if(ret != 0) 20 21 printf(create failed,%dn, ret); 22 exit(1); 23 24 pthread_join(t1, NULL); 25 while(1); 26 sleep(1); 27 return 0; 28 部分结果如下:(3076656016),15002(3076656016),15003(3076656016),15004(3076656016),15005(3076656016),15006(3076656016),15007可见线程id号被回收,并被用于创建新的线程。没有pthread_exit(),只有pthread_join()线程资源也能释放: 6 void *consumer(void *p) 7 8 static a = 0; 9 a+; 10 printf(%u),%dn, (unsigned)pthread_self(), a); 11 12 int main(int argc, char *argv) 13 14 pthread_t t1, t2, t3; 15 int ret; 16 do 17 ret = pthread_create(&t1, NULL, consumer, NULL); 18 if(ret != 0) 19 20 printf(create failed,%dn, ret); 21 exit(1); 22 23 pthread_join(t1, NULL); 24 while(1); 25 sleep(1); 26 return 0; 27 输出结果如下:(3076357008),19997(3076357008),19998(3076357008),19999只使用pthread_detach()分离子线程例子: 6 void *consumer(void *p) 7 8 static a = 0; 9 a+; 10 printf(%u),%dn, (unsigned)pthread_self(), a); 11 pthread_detach(pthread_self(); 12 return NULL; 13 14 int main(int argc, char *argv) 15 16 pthread_t t1, t2, t3; 17 int ret; 18 do 19 ret = pthread_create(&t1, NULL, consumer, NULL); 20 if(ret != 0) 21 22 printf(create failed,%dn, ret); 23 exit(1); 24 25 while(1); 26 27 return 0; 28 运行结果:只能创建一千个左右的线程,如下(3128908688),1184(3137301392),1185(3145694096),1186create failed,12分析原因可能是主线程创建线程速度太快,子线程还来不及释放资源,最终导致资源不足,下面在主函数里面加一个printf(),就不会出问题了。 14 int main(int argc, char *argv) 15 16 pthread_t t1, t2, t3; 17 int ret; 18 do 19 ret = pthread_create(&t1, NULL, consumer, NULL); 20 if(ret != 0) 21 22 printf(create failed,%dn, ret); 23 exit(1); 24 25 printf(); 26 while(1); 27 28 return 0; 29 部分结果如下:(2539965328),15210(3060312976),15211(3051920272),15212(3009956752),15213总结如下:1.线程自己运行结束,或者调用pthread_exit()结束,线程都会释放自己独立的空间资源。2.如果线程是非分离的,线程会保留线程id号,直到其他线程通过joining这个线程确认其已死亡。join 的结果是joining 线程得到已终止线程的退出状态,已终止的线程将消失。4.分离线程int pthread_detach(thread_t tid);函数用于指示应用程序在线程tid 终止时回收其存储空间。如果tid 尚未终止,pthread_detach() 不会终止该线程。返回值:pthread_detach() 在调用成功完成之后返回零。其他任何返回值都表示出现了错误。如果检测到以下任一情况,pthread_detach() 将失败并返回相应的值。EINVAL 描述: tid 是分离线程。ESRCH 描述: tid 不是当前进程中有效的未分离的线程。注意:为了避免线程的资源在线程结束时不能得到正确释放,从而避免产生潜在的内存泄漏问题,在对待线程结束时,要确保该线程处于detached 状态,否着就需要调用 pthread_join() 函数来对其进行资源回收。(如果不进行以上操作,线程id号不会被回收)。但是如果主线程结束,整个程序就结束了,所以最好在主线程使用,join等待其它线程结束。5.获取线程标识符pthread_t pthread_self(void);返回调用线程的标识符,(是一个无符号整形数)6.比较线程IDint pthread_equal(pthread_t tid1, pthread_t tid2);如果tid1 和tid2 相等,pthread_equal() 将返回非零值,否则将返回零。如果tid1 或tid2 是无效的线程标识号,则结果无法预测。7. 一次性初始化int pthread_once(pthread_once_t *once_control, void (*init_routine) (void)本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。例子: 1 #include 2 #include 3 #include 4 #include 5 pthread_once_t once = PTHREAD_ONCE_INIT; 6 7 void once_run(void) 8 9 printf(once_run in thread %un ,(unsigned int )pthread_self(); 10 11 12 void * child1(void * arg) 13 14 pthread_t tid =pthread_self(); 15 printf(thread: %u entern, tid); 16 pthread_once(&once,once_run); 17 printf(thread %u returnn, tid); 18 19 20 21 void * child2(void * arg) 22 23 pthread_t tid =pthread_self(); 24 printf(thread: %u entern, tid); 25 pthread_once(&once,once_run); 26 printf(thread %u returnn, tid); 27 28 29 int main(void) 30 31 pthread_t tid1,tid2; 32 printf(hellon); 33 pthread_create(&tid1,NULL,child1,NULL); 34 pthread_create(&tid2,NULL,child2,NULL); 35 sleep(5); 36 printf(main thread exitn); 37 return 0;38 运行结果:hellothread: 3067587472 enteronce_run in thread 3067587472 thread 3067587472 returnthread: 3075980176 enterthread 3075980176 returnmain thread exit8. 设置线程的调度策略和优先级int pthread_setschedparam(pthread_t tid, int policy,const struct sched_param *param);用于设置现有线程的调用策略和优先级。参数:tid需要设置的线程id号,policy 调度策略,param 优先级。线程的调度有三种策略:SCHED_OTHER、SCHED_RR和SCHED_FIFOSCHED_OTHER它是默认的线程分时调度策略,所有的线程的优先级别都是0,线程的调度是通过分时来完成的。简单地说,如果系统使用这种调度策略,程序将无法设置线程的优先级。请注意,这种调度策略也是抢占式的,当高优先级的线程准备运行的时候,当前线程将被抢占并进入等待队列。这种调度策略仅仅决定线程在可运行线程队列中的具有相同优先级的线程的运行次序。SCHED_FIFO它是一种实时的先进先出调用策略,且只能在超级用户下运行。这种调用策略仅仅被使用于优先级大于0的线程。它意味着,使用SCHED_FIFO的可运行线程将一直抢占使用SCHED_OTHER的运行线程J。此外SCHED_FIFO是一个非分时的简单调度策略,当一个线程变成可运行状态,它将被追加到对应优先级队列的尾部(POSIX 1003.1)。当所有高优先级的线程终止或者阻塞时,它将被运行。对于相同优先级别的线程,按照简单的先进先运行的规则运行。我们考虑一种很坏的情况,如果有若干相同优先级的线程等待执行,然而最早执行的线程无终止或者阻塞动作,那么其他线程是无法执行的,除非当前线程调用如pthread_yield之类的函数,所以在使用SCHED_FIFO的时候要小心处理相同级别线程的动作。SCHED_RR鉴于SCHED_FIFO调度策略的一些缺点,SCHED_RR对SCHED_FIFO做出了一些增强功能。从实质上看,它还是SCHED_FIFO调用策略。它使用最大运行时间来限制当前进程的运行,当运行时间大于等于最大运行时间的时候,当前线程将被切换并放置于相同优先级队列的最后。这样做的好处是其他具有相同级别的线程能在“自私“线程下执行。例子: 1 #include 2 #include 3 #include 4 #include 5 6 void *consumer(void *p) 7 8 int i; 9 printf(start (%d)n, (int)p); 10 for (i = 0; 1; i+) 11 12 if(i%200 = 10) 13 printf(%d)n, (int)p); 14 15 16 17 int main(int argc, char *argv) 18 19 pthread_t t1, t2, t3; 20 struct sched_param sched3; 21 sched3._sched_priority = 70; 22 23 pthread_create(&t1, NULL, consumer, (void *)4); 24 pthread_create(&t2, NULL, consumer, (void *)5); 25 pthread_create(&t3, NULL, (consumer), (void *)6); 26 27 sleep(8); 28 pthread_setschedparam(t3, SCHED_FIFO, &sched3); 29 30 pthread_join(t1, NULL); 31 pthread_join(t2, NULL); 32 pthread_join(t3, NULL); 33 return 0; 34 35 运行结果:前8秒交替打印 (4) 和(5)和 (6)8秒以后只打印 (6)注意:如果t3线程用sleep()阻塞自己,其它线程将会被调度执行。上面的程序在8秒后主线程(执行main)也不会执行,比如在29行增加一个exit(1),如果主线程会执行到29行,整个程序将结束,但实际上还会一直执行t3线程.主线程不会被执行。9. 获取线程的优先级int pthread_getschedparam(pthread_t thread, int *restrict policy, struct sched_param *restrict param);函数在成功完成之后返回零。其他任何返回值都表示出现了错误。如果出现以下情况,该函数将失败并返回对应的值。ESRCH 描述: tid 指定的值不引用现有的线程。例子: 1 #include 2 #include 3 #include 4 #include 5 6 void *consumer(void *p) 7 8 int i; 9 printf(start (%d)n, (int)p); 10 for (i = 0; 1; i+) 11 12 sleep(1); 13 printf(wake(%d)n, (int)p); 14 15 16 17 int main(int argc, char *argv) 18 19 pthread_t t1, t2, t3; 20 struct sched_param sched3, sched4; 21 sched3._sched_priority = 70; 22 int policy; 23 24 pthread_create(&t1, NULL, consumer, (void *)4); 25 pthread_create(&t2, NULL, consumer, (void *)5); 26 pthread_create(&t3, NULL, (consumer), (void *)6); 27 28 sleep(4); 29 pthread_setschedparam(t3, SCHED_FIFO, &sched3); 30 printf(main runn); 31 pthread_getschedparam(t3, &policy, &sched4); 32 printf(policy: %d, priority: %dn, policy, sched4._sched_priority); 33 exit(1); 34 35 pthread_join(t1, NULL); 36 pthread_join(t2, NULL); 37 pthread_join(t3, NULL); 38 return 0; 39 运行结果:start (6)start (5)start (4)wake(6)wake(5)wake(4)wake(6)wake(5)wake(4)wake(6)wake(5)wake(4)main runpolicy: 1, priority: 7010.取消线程 int pthread_cancel(pthread_t thread);设置取消点 void pthread_testcancel(void);测试是否接收到取消请求,如果有,结束线程。例子: 9 int a = 0; 10 void *thread1(void *arg) 11 12 pthread_testcancel(); 13 a = 10; 14 15 int main(int argc, char *argv) 16 17 pthread_t t1, t2, t3; 18 int ret, i; 19 printf(main startn); 20 ret = pthread_create(&t1, NULL, thread1, NULL); 21 pthread_cancel(t1); 22 pthread_join(t1, NULL); 23 sleep(3); 24 printf(main end, a=%dn, a); 25 return 0; 26 运行结果:在取消点处程序结束,a值未该。main startmain end, a=0如果改为: 9 int a = 0; 10 void *thread1(void *arg) 11 12 a = 10; 13 pthread_testcancel(); 14 运行结果:a值被修改了main startmain end, a=10例子: 9 void *thread1(void *arg) 10 11 printf(start thread (%u)n, (unsigned)pthread_self(); 12 printf(thread (%u) endn, (unsigned)pthread_self(); 13 14 int main(int argc, char *argv) 15 16 pthread_t t1, t2, t3; 17 int ret; 18 printf(main startn); 19 ret = pthread_create(&t1, NULL, thread1, NULL); 20 if(ret != 0) 21 22 printf(create thread failedn); 23 exit(1); 24 25 pthread_cancel(t1); 26 sleep(5); 27 printf(main endn); 28 return 0; 29 运行结果:main startstart thread (3076238224)main end注意:子线程并没设置取消点,但是却被取消了,原因是printf函数包含了一个个取消点(应该在函数结尾),在取消点检测到取消请求时结束线程,第二个printf不会运行,如果在printf前加一个取消点,线程在printf运行前被取消了,不会有结果输出。如下: 9 void *thread1(void *arg) 10 11 pthread_testcancel(); 12 printf(start thread (%u)n, (unsigned)pthread_self(); 13 printf(thread (%u) endn, (unsigned)pthread_self(); 14 运行结果:main startmain end取消线程,是否会释放线程的所有资源?例子: 9 void *thread1(void *arg) 10 11 printf(start thread (%u)n, (unsigned)pthread_self(); 12 13 int main(int argc, char *argv) 14 15 pthread_t t1, t2, t3; 16 int ret; 17 printf(main startn); 18 do 19 ret = pthread_create(&t1, NULL, thread1, NULL); 20 if(ret != 0) 21 22 printf(create thread failedn); 23 exit(1); 24 25 pthread_cancel(t1); 26 if(ret != 0) 27 28 printf(join failedn); 29 exit(1); 30 31 while(1); 32 return 0; 33 运行结果:start thread (349191056), 327start thcreate thread failed注意:每次运行的结果都不一样,在主线程里面加了printf限制产生线程的速度,但是能生成的线程数都在350个左右,应该可以判断,取消并没完全释放资源。所以取消线程后,还应该用join来完全释放资源:如下:14 int main(int argc, char *argv) 15 16 pthread_t t1, t2, t3; 17 int ret, i; 18 printf(main startn); 19 do 20 ret = pthread_create(&t1, NULL, thread1, NULL); 21 if(ret != 0) 22 23 printf(create thread failedn); 24 exit(1); 25 26 pthread_cancel(t1); 27 printf(); 28 pthread_join(t1, NULL); 29 if(ret != 0) 30 31 printf(join failedn); 32 exit(1); 33 34 while(1); 35 return 0; 36 运行结果:将不断创建新线程.注意:取消线程相当于使用pthread_exit终止线程。启用或禁用取消功能:int pthread_setcancelstate(int state, int *oldstate);oldstate放置旧的取消状态pthread_setcancelstate() 在成功完成之后返回零。例子:int oldstate;int ret;/* enable

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论