目录
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:父进程执行,数据存在缓冲区
运行结果: