目录
1. fork创建子进程继承父进程缓冲区验证
1.1 write向标准输出(终端屏幕)写入数据验证
1.1.1 write函数写入数据不带行缓冲刷新 \n
1.1.2 write函数写入数据带行缓冲刷新 \n
1.2 fork创建前执行printf函数
1.2.1 fork创建前执行printf函数带\n,刷新缓冲区
1.2.2 fork创建前执行printf函数不带\n,缓冲区有缓冲数据
1.3 fork缓冲输出重定向
1.3.1 fork缓冲输出重定向到文件
1.3.2 fork缓冲输出重定向到文件,验证write无缓冲直接输出
1. fork创建子进程继承父进程缓冲区验证
1.1 write向标准输出(终端屏幕)写入数据验证
write函数为系统调用,无缓冲区,写入数据直接输出到终端。
1.1.1 write函数写入数据不带行缓冲刷新 \n
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>int main(int argc, char *argv[])
{printf("main 开始\n");int length = 0;char buf[] = "a write to stdout";//向标准输出(终端屏幕)写入buf数据//write函数为系统调用,无缓冲区,数据直接输出到终端。length = write(1, buf, strlen(buf));if(length != strlen(buf)){printf("write error\n");}return 0;
}
运行结果:
1.1.2 write函数写入数据带行缓冲刷新 \n
程序:
仅修改上述程序中的 : char buf[] = "a write to stdout\n";
运行结果:
1.2 fork创建前执行printf函数
1.2.1 fork创建前执行printf函数带\n,刷新缓冲区
printf函数带\n,刷新缓冲区,子进程继承父进程缓冲区里面无内容。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>int main(int argc, char *argv[])
{printf("main 开始\n");pid_t pid;int length = 0;char buf[] = "a write to stdout\n";//char buf[] = "a write to stdout";//向标准输出(终端屏幕)写入buf数据//write函数为系统调用,无缓冲区,直接输出到终端。length = write(1, buf, strlen(buf));if(length != strlen(buf)){printf("write error\n");}//验证不带 \n,子进程会继承,终端缓冲区内容。// printf 有\n 时,行缓冲区会刷新,刷新后缓冲区无内容。printf("fork 创建前:\n");pid=fork();if(pid<0){perror("fail to fork");}else if(pid==0){printf("在子进程中- \n");}else{sleep(1);//让子进程先执行完,在执行父进程printf("在父进程中- \n");}return 0;
}
运行结果:printf函数带\n,执行printf("fork 创建前:\n"); 刷新了缓冲区,子进程继承父进程缓冲区里面无内容。不会打印fork之前的printf内容。
1.2.2 fork创建前执行printf函数不带\n,缓冲区有缓冲数据
printf 无\n 时,行缓冲区不会刷新(除非行缓冲数据存满1024字节),缓冲区有缓冲数据。
下次刷新缓冲区时,缓冲区数据会输出。
程序:
仅修改上述程序的 printf("fork 创建前:"); 去掉printf函数的 \n
运行结果:由于执行 printf("fork 创建前:");,printf函数无 \n,缓冲区不会刷新,打印的内容:fork 创建前:,一直存在缓冲区中,没有输出。在fork 创建子进程时,父进程缓冲区数据被子进程继承,等到缓冲区刷新时,才会将 缓冲数据输出。
打印的数据 (main 开始,已不再缓冲区中 ; a write to stdout 无缓冲,已直接输出)。
fork 创建前:在子进程中- //子进程程序运行,输出
fork 创建前:在父进程中- //父进程程序运行,输出
1.3 fork缓冲输出重定向
重定向:将终端输出结果,重新定向到文件,缓冲区变为全缓冲。
fork缓冲输出重定向到文件,原来的行缓冲变为全缓冲,只有缓冲区满、人为调用刷新函数(fflush)、程序运行结束才会刷新。即使 printf函数带\n,也不会刷新缓冲区。
1.3.1 fork缓冲输出重定向到文件
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>int main(int argc, char *argv[])
{//printf("main 开始\n");pid_t pid;int length = 0;char buf[] = "a write to stdout\n";//char buf[] = "a write to stdout";//向标准输出(终端屏幕)写入buf数据//write函数为系统调用,无缓冲区,直接输出到终端。length = write(1, buf, strlen(buf));if(length != strlen(buf)){printf("write error\n");}//验证不带 \n,子进程会继承,终端缓冲区内容。// printf 有\n 时,行缓冲区会刷新,刷新后缓冲区无内容。// printf 无\n 时,行缓冲区不会刷新(除非行缓冲数据存满1024字节),缓冲区有缓冲数据。//下次刷新缓冲区时,缓冲区数据会输出。printf("fork 创建前:\n");pid=fork();if(pid<0){perror("fail to fork");}else if(pid==0){printf("在子进程中- \n");}else{sleep(2);//让子进程先执行完,在执行父进程printf("在父进程中- \n");}return 0;
}
运行结果:
(1)终端运行结果
printf函数带\n,执行printf("fork 创建前:\n"); 刷新了缓冲区,子进程继承父进程缓冲区里面无内容。不会打印fork之前的printf内容。写入的的数据 ( a write to stdout 无缓冲,已直接输出)。
(2)执行./a.out > test.txt ,输出重定向到文件
fork缓冲输出重定向到文件,原来的行缓冲变为全缓冲,只有缓冲区满、人为调用刷新函数(fflush)、程序运行结束才会刷新。即使 printf函数带\n,也不会刷新缓冲区。
运行结果:
写入的的数据 ( a write to stdout 无缓冲,直接输出)。
执行printf("fork 创建前:\n"); 原本会刷新了缓冲区,但重定向后,行缓冲变为全缓冲,\n不会刷新缓冲区。子进程继承了父进程缓冲区数据,子进程执行时,也会打印:fork 创建前:\n;
1.3.2 fork缓冲输出重定向到文件,验证write无缓冲直接输出
在main函数开始,加入 printf("main 开始\n");
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>int main(int argc, char *argv[])
{printf("main 开始\n");pid_t pid;int length = 0;char buf[] = "a write to stdout\n";//char buf[] = "a write to stdout";//向标准输出(终端屏幕)写入buf数据//write函数为系统调用,无缓冲区,直接输出到终端。length = write(1, buf, strlen(buf));if(length != strlen(buf)){printf("write error\n");}//验证不带 \n,子进程会继承,终端缓冲区内容。// printf 有\n 时,行缓冲区会刷新,刷新后缓冲区无内容。// printf 无\n 时,行缓冲区不会刷新(除非行缓冲数据存满1024字节),缓冲区有缓冲数据。//下次刷新缓冲区时,缓冲区数据会输出。printf("fork 创建前:\n");pid=fork();if(pid<0){perror("fail to fork");}else if(pid==0){printf("在子进程中- \n");}else{sleep(2);//让子进程先执行完,在执行父进程printf("在父进程中- \n");}return 0;
}
运行结果:
(1)终端运行
printf("fork 创建前:\n"); 带有行缓冲刷新 \n ,子进程继承父进程缓冲区时,父进程缓冲区无数据,不会打印fork 创建前:
(2)执行./a.out > test.txt ,输出重定向到文件
函数运行时,从main函数开始:
①首先执行,printf("main 开始\n"); 但是,由于重定向后,行缓冲变为全缓冲,\n不会刷新缓冲区(只有缓冲区满、人为调用刷新函数(fflush)、程序运行结束才会刷新)。
子进程继承了父进程缓冲区数据,printf("main 开始\n");,子进程执行时,等待缓冲区刷新时,才会输出数据。
②执行写入函数 write(1, buf, strlen(buf));,写入数据,由于写入的的数据 ( a write to stdout 无缓冲,将会直接输出到终端)。
③执行printf("fork 创建前:\n"); 原本会刷新了缓冲区,但重定向后,行缓冲变为全缓冲,\n不会刷新缓冲区。
子进程继承了父进程缓冲区数据,printf("fork 创建前:\n"); ,子进程执行时,等待缓冲区刷新时,才会输出数据。
④子进程执行完,父进程执行,打印输出过程与子进程相同。
终端打印数据顺序分析:全缓冲,没有调用刷新函数,函数程序运行结束才会刷新缓冲区。
函数执行过程:
printf("main 开始\n"); //顺序2:子进程执行,数据存在缓冲区
write(1, buf, strlen(buf)); //顺序1:子进程执行时,最先输出到终端,无缓冲。
printf("fork 创建前:\n"); //顺序3:子进程执行,数据存在缓冲区
printf("在子进程中- \n"); //顺序4:子进程执行,数据存在缓冲区
printf("main 开始\n"); /顺序5:父进程执行,数据存在缓冲区
printf("fork 创建前:\n"); /顺序6:父进程执行,数据存在缓冲区
printf("在父进程中- \n"); /顺序7:父进程执行,数据存在缓冲区
运行结果: