1. 前言 “我的人品有这么差吗!半个小时Linux都没调度我的线程!”。 前些日子同事抱怨,“linux是多线程系统,每个线程都有一个时间片,为什么我的程序似乎一直没被调度”,随即给我演示执行过程。大致归纳成下面的代码逻辑。 程序启动后仅仅输出一行“run”,然后就没有然后了,喝着咖啡、嗑着瓜子、带薪摸鱼,屏幕上干干净净。理想状态下每10秒执行任务完毕后输出“do”。 分析代码逻辑可知 “推断” 代码是否被运行的依据是屏幕上输出 “do” ,”而这真的科学吗?答案是否定的,linux有着雨露均沾的调度系统,很难做到半小时没被调度。问题就出在linux的 “行缓冲”机制 。 - # J8 J( C0 w2 ~7 a
- void main()
# R% e0 ~; T& z/ u9 }* V. l$ [2 o7 k - {
- V9 b* a! I+ k; t7 G) N - printf("run\n");/ p5 r, J# U3 m4 }& V0 u
- while(1) {3 h! E& i; f5 e; O( X# @
- sleep(10);
& o- m% g# |9 g1 ?4 ^& S6 C7 v - do_thing();
% I7 Z0 ~ T- ~ - printf("do");- g* m8 ~; J$ ~" v/ y" R
- }$ z. l- g% R9 G" C$ f8 j5 z# R
- }
复制代码
7 q8 ]0 H: I D) U
* z* W. K+ x" q) r" s5 B 2. 行缓冲
) c. f4 ?/ I4 [" w% r: N
上文的printf输出目标设备由STDOUT指定,STDOUT可能指向115200波特率的串口设备,也可能指向本地图形设备,相对于CPU而言他们的速度要慢上几个数量级。都是为了提高机器或者程序的性能、提高CPU利用率。协调高速设备和低速设备之间速度的不匹配,操作系统默认在标准I/O上采用行缓冲机制,printf的内容首先存储在内存,当缓冲填满或检测到换行符’’时则输出到目标设备。 Linux上这个行缓冲默认是1024Byte,每10s输出do占用2Byte,为了等待缓冲填满需要等待81min。 知道原理后解决方法就简单了。 方法1:fflush强制刷新标准输出stdout
6 L, B! S7 K0 [- z- l2 ?. z- #include
f! n. F: h' @6 Y - void main()
/ N; b2 C0 X, F- R$ o+ X F - {
" ?& @# c0 H& }) f( w& U - printf("run\n");
3 J$ |' U- \8 W* e - while(1) {
. u& I7 |+ k! B# K - sleep(10);
4 _6 z2 E0 A, q' h3 b: } - do_thing();4 @% J9 m3 b) R) ?+ r, a; w+ L
- fflush(stdout);
/ L, t8 @3 ?; M$ r - printf("do");9 X( t( @& U7 Q# r+ O. E
- }9 [: n# b0 K% D
- }
. ^9 E* G0 r* k" C' p2 @* p
复制代码 6 e" V. n G8 ^1 L7 ~/ _ d
方法2:输出“换行符”) k' v2 i% @3 c; Z4 H* ?9 ]
# P1 Y( c' g0 d' U5 f: x; Z. c- #include 1 X& N9 P5 V8 O U n% g
- void main()
" t# F; V+ a* a4 n - {. p+ L2 y$ w) E" _2 S
- printf("run\n");! {& k6 @/ e: R* S+ a: [7 [
- while(1) {; A) i: c* ~% y8 a3 F; M
- sleep(10);
; {+ f! K8 b4 q' A1 R h0 y1 q - do_thing();9 q% _. T$ p. e+ O
- printf("do\n");3 v5 C7 M; T# K2 }% I6 I/ ^3 r9 d4 K3 j
- }2 y5 v4 s. s8 r, s+ f
- }
复制代码
5 Y( W `! i3 q8 U& c; H |