lecture05是并发的第一节课。主要讲了入门(两个API,create和join)和放弃(原来很自然的串行想法)
- 并发线程模型
- 最小线程库
- 线程自问自答
- 1+1
- 思考题:3个T_sum线程,sum的结果最小是多少?
- 补充实验
并发线程模型
代码:
用mosaic检查(怎么将mosaic封装成命令行工具)
(这里观察输出结果,会发现3消失了,5还重复了两次。)
最小线程库
thread.h是后续几乎所有例子都用到的头文件,可以将它放到固定位置,然后将路径放到环境变量中。(我没有,我改了后续例子的Makefile中的变量TLIB_PATH)
运行hello,发现ab交替的打印。top -d 0.5
查看cpu使用情况,发现hello占用了将近200%的cpu。
这里有个问题,怎么占用率会大于1呢?
解答: % cpu 是表示单核 cpu 的占用率, 而不是占用所有 cpu 的占用率. 即如果我们是 8 核 cpu, 那么 800% 才是最高的 cpu 利用率。比如说有个程序App每个核心上都用了30%,那么看这个APP对应的CPU的使用率就是240%,机器总体的占用率只有40%。
线程自问自答
memory.c证明了T_a 和 T_b 真的共享内存。
stack.c证明线程具有独立堆栈 ,并且确定了堆栈的范围。
Makefile要做如下修改:
make后运行stack
运行memory
make run,可以运行两个。并且在这里把stack的输出取了最大值,可以看到每个线程堆栈空间是8K
1+1
就算sum++改成内嵌汇编也不行。(后续回顾:使用sum++结果不对的原因跟山寨支付宝一样。内嵌汇编结果不对的原因在于多处理器中每个处理器看到的sum不是同一个sum)
拓展:printf有一个缓冲区,跟多个线程同时修改sum的情况类似。好在printf是线程安全的。若否,当两个线程同时往缓冲区内加入内容时,你就会发现打印也打不对了。
思考题:3个T_sum线程,sum的结果最小是多少?
答案是2
弹幕:每个线程内部顺序不能被打乱, 但线程之间全局顺序可以交织,某个线程中最后一个循环不可能读到sum=0, 因为该线程前两个循环会保证sum!=0
2怎么来的:
===== ===== =====
T1取0T2取0
T1加
T1存1
T1取1
T1加
T1存2
T1取2
T1加
T1存3T2加T2存1
T1取1
T1加T3……(结束)T2……(结束)
T1存2
(结束)
===== ===== =====
结果:sum=2
通过这个例子,只能说人类 (我) 真不擅长理解并发
补充实验
当使用内嵌汇编并且是单处理器时,结果是正确的