收藏 分销(赏)

LinuxPthread深入解析.doc

上传人:精*** 文档编号:2182982 上传时间:2024-05-22 格式:DOC 页数:14 大小:23.65KB
下载 相关 举报
LinuxPthread深入解析.doc_第1页
第1页 / 共14页
LinuxPthread深入解析.doc_第2页
第2页 / 共14页
LinuxPthread深入解析.doc_第3页
第3页 / 共14页
LinuxPthread深入解析.doc_第4页
第4页 / 共14页
LinuxPthread深入解析.doc_第5页
第5页 / 共14页
点击查看更多>>
资源描述

1、Outline- 1.线程特点- 2.pthread创建- 3.pthread终止 - 4.mutex互斥量使用框架 - 5.cond条件变量 - 6.综合实例=1. 线程特点线程拥有自己独立的栈、调度优先级和策略、信号屏蔽字(创建时继承)、errno变量以及线程私有数据。进程的其他地址空间均被所有线程所共享,因此线程可以访问程序的全局变量和堆中分配的数据,并通过同步机制保证对数据访问的一致性。2. pthread创建pthread有一个线程ID,类型为pthread_t,在使用printf打印时,应转换为u类型。pthread_equal可用于比较两个id是否相等;pthread_self用

2、于获取当前线程的ID。pthread_create用于创建新的线程,可以给线程传入一个void *类型的参数,例如一个结构体指针或者一个数值。系统并不能保证哪个线程会现运行:新创建的线程还是调用线程。3. pthread终止a) 从线程函数中返回b) 被同一进程中的其他线程取消c) 线程调用pthread_exit注意,线程的返回值需要转换为void *类型。pthread_exit(void *ret)pthread_join(pthread_t id, void *ret)ret均可设置为NULL4. mutex 互斥量使用框架pthread_mutex_t lock;pthread_mu

3、tex_init 或者 PTHREAD_MUTEX_INITIALIZER(仅可用在静态变量)pthread_mutex_lock / pthread_mutex_unlock / pthread_mutex_trylockpthread_mutex_destroy5. cond 条件变量pthread_cond_t qready;pthread_mutex_t qlock;pthread_mutex_init 或者 PTHREAD_MUTEX_INITIALIZERpthread_cond_init 或者 PTHREAD_COND_INITIALIZERpthread_mutex_lock(

4、&qlock.)pthread_cond_wait(&qready, &qlock.) / pthread_cond_timewaitpthread_mutex_unlock(&qlock)pthread_cond_destroy/唤醒条件变量pthread_cond_signalpthread_cond_broadcast条件变量是pthread中比较难以理解的一点,主要会产生以下疑惑:Q1. 假如在调用pthread_cond_wait | cond_timedwait之前就调用pthread_cond_signal | broadcast会发生什么?Q2. pthread_cond_co

5、nd_wait | cond_timewait为什么需要一个已经锁住的mutex作为变量?Q3. pthread_cond_signal | broadcast使用之前必须获取wait中对应的mutex吗?Q4. 假如pthread_cond_signal | broadcast必须获取mutex,那么下列两种形式,哪种正确?为什么?1)lock(lock_for_X);change(X);unlock(lock_for_X);pthread_cond_signal | broadcast;2)lock(lock_for_X);change(X);pthread_cond_signal | b

6、roadcast;unlock(lock_for_X);-思考-思考-思考-思考-思考-思考-思考-思考-思考-A1: 什么都不会发生,也不会出错,仅仅造成这次发送的signal丢失。A2: 一般场景如下,我们需要检查某个条件是否满足(如队列X是否为空、布尔Y是否为真),假如没有条件变量,我们唯一的选择是1. while (1) 2. lock(lock_for_X);3.4. if (X is not empty) 5. unlock(lock_for_X);6. break;7. else /X is empty, loop continues8. unlock(lock_for_X);9

7、. sleep(10);10. 11. 12. /X is not empty, loop ends13. process(X);明显这种轮询的方式非常耗费CPU时间,这时候我们很容易的想到,如果有一种机制,可以异步通知我们队列的状态发生了变化,那么我们便无须再轮询,只要等到通知到来时再检查条件是否满足即可,其他时间则将程序休眠,因此现在代码变成这样:1. while (1) 2. lock(lock_for_X);3. if (X is not empty) 4. unlock(lock_for_X);5. break;6. else 7. unlock(lock_for_X); /must

8、 called before my_wait(), otherwise no one can acquire the lock and make change to X8. -窗口,由于已经解锁,其他程序可能改变X,并且试图唤醒mywait,但在一个繁忙的系统中,可能此时my_还没被调用!9. my_wait(); /go to sleep and wait for the notification10. 11. my_wait是一个假想的函数,作用如注释所示。不难发现,这样做以后,我们无须再轮询了,只需要等待my_wait()被唤醒以后检查条件是否满足。但是请注意,正如图中所示,存在1个时间

9、窗口。若其他程序在这个窗口中试图唤醒my_wait,由于此时my_wait还没有被调用,那么这个信号将丢失,造成my_wait一直阻塞。解决的办法就是,要将unlock和my_wait合并成一个原子操作,这样就不会被其他程序插入执行。我想到这里,你应该已经明白了,这个原子操作的函数就是pthread_cond_signal | broadcast.A3: 是的。详见:A4: 对于1),在不同的操作系统中,可能会造成不确定的调度结果(可能会造成调度优先级反转);对于2)可以保证无论在何种操作系统中都将获得预期的调度顺序。设想一个场景:有两个消费者线程A和B,我们设定A的优先级比B高,A正在等待条

10、件变量被出发,即已经调用了pthread_wait,并且处于阻塞状态:1. lock(lock_for_X);2. while (X is empty) 3. pthread_cond_wait(&qready, &lock_for_X);4. 5. unlock(lock_for_X);B中没有调用pthread_wait,而是做类似如下的处理:1. while(1) 2. lock(lock_for_X);3. dequeue(X);4. unlock(lock_for_X);5. 另一个线程C,为生产者,采用1)方案,则代码如下,先unlock,再发出signal:lock(lock_f

11、or_X);change(X);unlock(lock_for_X);pthread_cond_signal | broadcast;当发出unlock以后,发送signal之前,此时消费者B已经满足了运行条件,而消费者A虽然优先级比B高,但是由于其运行条件还需要signal,所以不具备立刻运行的条件,此时就看操作系统如何实现调度算法了。有些操作系统,可能会因为A不具备立刻运行条件,即使它的优先级比B高,此时还是让B线程先运行,那么,后续将分成两种情况:(a) B获得了lock,但是还没有将X队列中的刚刚加入的条目移除,此时C调用了signal,A接收到了signal,由于A的优先级高,那么A

12、抢占B,A从函数pthread_cond_wait返回之前需要再次将lock上锁,但是A抢占后发现,lock被人锁住了(还没有被B释放),只好再次休眠,等待锁被释放,结果B又被唤醒,也可能因此造成A和B的死锁,这个具体要看操作系统的调度算法。(b) B获得了lock,并且执行了dequeue,然后释放了锁。此时C调用了signal,A接收到了signal,由于A的优先级高,那么A抢占B,A这次顺利的获取了锁得以从pthread_cond_wait中返回,但是在检查条件时,却发现队列是空的,于是乎再次进入pthread_cond_wait休眠。结果A又无法被执行,A可能由此进入饥饿状态。但是如果

13、C采用2)方案:lock(lock_for_X);change(X);pthread_cond_signal | broadcast;unlock(lock_for_X);在unlock以后,A、B都具备了立即运行的条件,由于A比B的优先级高,因此操作系统必定会先调度A执行,就避免了前面一种不确定的调度结果。主要参考:6. 综合实例/*2. * =3. *4. * Filename: pthread.c5. *6. * Description: 7. *8. * Version: 1.09. * Created: 08/17/11 11:06:3510. * Revision: none11.

14、 * Compiler: gcc12. *13. * Author: YOUR NAME (), 14. * Company: 15. *16. * =17. */18. #include 19. #include 20. #include 21. #include 22. #include 23. #include 24. 25. pthread_cond_t qready;26. pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;27. 28. struct foo 29. int cnt;30. pthread_mutex_t f_loc

15、k;31. ;32. 33. void cleanup(void *arg)34. 35. printf(clean up: %sn, (char *)arg);36. 37. 38. void printids(char *str)39. 40. printf(%s pid = %u tid = %u / 0x%xn, 41. str, (unsigned int)getpid(), (unsigned int)pthread_self(), (unsigned int)pthread_self();42. 43. 44. void *thread1(void *arg)45. 46. pt

16、hread_mutex_lock(&qlock);47. pthread_cond_wait(&qready, &qlock);48. pthread_mutex_unlock(&qlock);49. 50. printids(thread1:);51. 52. pthread_cleanup_push(cleanup, thread 1 first cleanup handler);53. pthread_cleanup_push(cleanup, thread 1 second cleanup handler);54. printf(thread 1 push complete!n);55

17、. 56. pthread_mutex_lock(&(struct foo *)arg)-f_lock);57. (struct foo *)arg)-cnt ;58. printf(thread1: cnt = %dn, (struct foo *)arg)-cnt);59. pthread_mutex_unlock(&(struct foo *)arg)-f_lock);60. 61. if (arg) 62. return (void *)0);63. 64. pthread_cleanup_pop(0);65. pthread_cleanup_pop(0);66. 67. pthrea

18、d_exit(void *)1);68. 69. 70. void *thread2(void *arg)71. 72. int exit_code = -1;73. printids(thread2:);74. 75. printf(Now unlock thread1n);76. 77. pthread_mutex_lock(&qlock);78. pthread_mutex_unlock(&qlock);79. pthread_cond_signal(&qready);80. 81. printf(Thread1 unlockedn);82. 83. pthread_cleanup_pu

19、sh(cleanup, thread 2 first cleanup handler);84. pthread_cleanup_push(cleanup, thread 2 second cleanup handler);85. printf(thread 2 push complete!n);86. 87. if (arg) 88. pthread_exit(void *)exit_code);89. 90. pthread_cleanup_pop(0);91. pthread_cleanup_pop(0);92. 93. pthread_exit(void *)exit_code);94.

20、 95. 96. int main(int argc, char *argv)97. 98. int ret;99. pthread_t tid1, tid2;100. void *retval;101. struct foo *fp;102. 103. ret = pthread_cond_init(&qready, NULL);104. if (ret != 0) 105. printf(pthread_cond_init error: %sn, strerror(ret);106. return -1;107. 108. 109. 110. 111. if (fp = malloc(si

21、zeof(struct foo) = NULL) 112. printf(malloc failed!n);113. return -1;114. 115. 116. if (pthread_mutex_init(&fp-f_lock, NULL) != 0) 117. free(fp);118. printf(init mutex failed!n);119. 120. 121. pthread_mutex_lock(&fp-f_lock);122. 123. ret = pthread_create(&tid1, NULL, thread1, (void *)fp);124. if (re

22、t != 0) 125. printf(main thread error: %sn, strerror(ret);126. return -1;127. 128. ret = pthread_create(&tid2, NULL, thread2, (void *)1);129. if (ret != 0) 130. printf(main thread error: %sn, strerror(ret);131. return -1;132. 133. 134. 135. ret = pthread_join(tid2, &retval);136. if (ret != 0) 137. p

23、rintf(pthread join falied!n);138. return -1;139. 140. else141. printf(thread2 exit code %dn, (int)retval);142. 143. fp-cnt = 1;144. printf(main thread: cnt = %dn,fp-cnt);145. 146. pthread_mutex_unlock(&fp-f_lock);147. 148. sleep(1); /there is no guarantee the main thread will run before the newly created thread, so we wait for a while 149. printids(main thread:);150. 151. printf(Press to exitn);152. 153. ret = pthread_cond_destroy(&qready);154. if (ret != 0) 155. printf(pthread_cond_destroy error: %sn, strerror(ret);156. return -1;157. 159. getchar();160. return 0;161.

展开阅读全文
相似文档                                   自信AI助手自信AI助手
猜你喜欢                                   自信AI导航自信AI导航
搜索标签

当前位置:首页 > 考试专区 > 中考

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2024 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服