write, fwrite,printf等它们都会与buffer有关,有时向日志中写data,第二天发现data没有保存完整,出现这个问题,都是buffering的问题,下面从linux系统来分析buffering。
buffering种类
- non-buffering
无缓存,写入数据立即写入 - line-buffering
遇到newline,即换行符时写入 - full-buffering
buffer没有写满,或没有强制,都不会立即写入的
栗子(line-buffering)
25 int globvar = 6;
26 char buf[] = " a write to stdout\n";
262 int var;
263 pid_t pid;
264 int main() {
265 var = 88;
266 if (write(STDOUT_FILENO, buf, strlen(buf)) != strlen(buf)) {
268 printf("write error\n");
269 exit(1);
270 }
271 printf("before fork\n");
272
273 if ((pid = fork()) < 0){
274 printf("fork error\n");
275 exit(2);
276 } else if (pid == 0) {
277 globvar++;
278 var++;
279 }else {
280 sleep(2);
281 }
282 printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
283 exit(0);
}
交互执行:
jack@jxes-VirtualBox:~/samba_share/apue$ gcc test.c
jack@jxes-VirtualBox:~/samba_share/apue$ ./a.out
a write to stdout
before fork
pid = 24650, glob = 7, var = 89
pid = 24649, glob = 6, var = 88
重定位:
jack@jxes-VirtualBox:~/samba_share/apue$ ./a.out > tm.txt
jack@jxes-VirtualBox:~/samba_share/apue$ ls
a.out apue.3e apue.h in.txt test.c testjmp.c tm.txt
jack@jxes-VirtualBox:~/samba_share/apue$ cat tm.txt
a write to stdout
before fork
pid = 24658, glob = 7, var = 89
before fork
pid = 24657, glob = 6, var = 88
上面栗子中,如果将执行结果redirect到文件中,before fork会被输出两次。这就是因为在fork之前,printf到buffer里的内容交没有立即写入,因为此时被重定向到文件中去了,而不是标准输出stdout,所以这时,before fork还在memory中,当执行fork时会把parent的data space中的内容copy给child process,自然也就连同存在里面的before fork一些被copy给child process了,这也就是在parent和child process中都会被输出的原因。
而直接以交互方式输出时,由于第一种方式是直接输出到stdout,是line-buffering方式,即遇到换行符”\n”时,内容就被写入,如果没有”\n”,情况就会与重定向一致,修改下代码如下:
.......
271 printf("before fork"); //去掉\n
272
273 if ((pid = fork()) < 0){
........
jack@jxes-VirtualBox:~/samba_share/apue$ gcc test.c
jack@jxes-VirtualBox:~/samba_share/apue$ ./a.out
a write to stdout
before forkpid = 24925, glob = 7, var = 89
before forkpid = 24924, glob = 6, var = 88
切记
平时在写文件时,一定要记得把内容写入,比如写文件时,通常用fflush。
另外,分配内存空间时主要区分上面三种类型。