写时拷贝:提高了fork复制的效率
int main()
{
for(int i=0;i<2;i++)
{
fork();
printf("A\n");
}
}
打印6个A
父进程 i=0 fork A; i=1 fork A;
右子进程(i=0 此时从fork后开始执行)A; i=1 fork A
左下子进程(i=1)A;
右下子进程(i=1)A;
int main()
{
for(int i=0;i<2;i++)
{
fork();
printf("A");
}
}
打印8个A,原本父进程打了一个A,复制的时候,缓存区也会存着A给子进程
父进程 i=0 fork A(缓冲区); i=1 fork A;
右子进程(i=0 此时从fork后开始执行)A(存在缓冲区); i=1 fork A
左下子进程(i=1)父缓冲区A+A;
右下子进程(i=1)右子缓冲区A+A;
int main()
{
fork()||fork();
printf("A\n");
}
打印3个A
C语言中||:他会先算前一部分,如果前一部分为真,他将停止运算,如果为假,他才会算第二部分,你这里第一部分就为真了,第二部分当然也就不会算了。
父进程 fork()||fork(); 只执行第一个fork(fork>0),执行后杀死,打印了一个A
子进程 fork()||fork(); 被杀死的第一个fork(==0),因此执行第二个fork(复制出一个子进程),打印一个A
子进程的子进程 fork()||fork(); 被杀死的第一个fork(==0),被杀死第二个fork(==0),打印一个A
int main()
{
fork()&&fork();
printf("A\n");
}
打印三个A
C语言中:&&且操作 ,&&为界将表达式分为两部分,他会先算前一部分,如果前一部分为假,他将停止运算,如果为真,他才会算第二部分,你这里第一部分就为假了,第二部分当然也就不会算了。
父进程 fork()&&fork(); 执行第一个fork(fork>0),生成子进程1,执行第二个fork,生成子进程2,打印一个A
子进程1 fork()&&fork(); 被杀死的第一个fork(fork==0),不执行第二个fork,打印了一个A
子进程2 fork()&&fork(); 被杀死的第一个fork(fork>0),被杀死的第二个fork(fork==0),打印一个A
僵死(僵尸)进程:子进程先结束,父进程没有调用wait获取子进程的退出码,子进程就变成了僵死进程
(PCB没有被删掉)
#include
#include
#include
#include
#include
int main()
{
int n=0;
char*s=NULL;
pid_t pid=fork();
assert(pid!=-1);
if(pid==0)
{
n=3;
s="child";
}
else
{
n=10;
s="parent";
}
for(int i=0;i<n;i++)
{
printf("s=%s\n",s);
sleep(1);
}
exit(3);
}
后台运行,ps查看->可显示僵死进程
stu@stu-virtual-machine:~/Linux/day08$ ./test&
[1] 3669
stu@stu-virtual-machine:~/Linux/day08$ s=parent
s=child
s=child
s=parent
ps
PID TTY TIME CMD
2550 pts/0 00:00:00 bash
3669 pts/0 00:00:00 test
3670 pts/0 00:00:00 test
3671 pts/0 00:00:00 ps
stu@stu-virtual-machine:~/Linux/day08$ s=child
s=parent
s=parent
s=parent
ps
PID TTY TIME CMD
2550 pts/0 00:00:00 bash
3669 pts/0 00:00:00 test
3670 pts/0 00:00:00 test <defunct>
3672 pts/0 00:00:00 ps
stu@stu-virtual-machine:~/Linux/day08$ s=parent
s=parent
s=parent
s=parent
s=parent
获得退出码(man 3 wait)
#include
pid_t wait(int *stat loc)
test.c
#include
#include
#include
#include
#include
#include
int main()
{
int n=0;
char*s=NULL;
pid_t pid=fork();
assert(pid!=-1);
if(pid==0)
{
n=3;
s="child";
}
else
{
n=10;
s="parent";
int val=0;
wait(&val);
printf("exit_code=%d\n",val);
}
for(int i=0;i<n;i++)
{
printf("s=%s\n",s);
sleep(1);
}
exit(3);
}
结果
stu@stu-virtual-machine:~/Linux/day08$ ./test
s=child
s=child
s=child
exit_code=768
s=parent
s=parent
s=parent
s=parent
s=parent
s=parent
s=parent
s=parent
s=parent
s=parent
768>>8 = 3
判断程序正常结束 获得退出码
test.c
#include
#include
#include
#include
#include
#include
int main()
{
int n=0;
char*s=NULL;
pid_t pid=fork();
assert(pid!=-1);
if(pid==0)
{
n=3;
s="child";
}
else
{
n=10;
s="parent";
int val=0;
wait(&val);
if(WIFEXITED(val))//判断程序正常结束
{
printf("exit_code=%d\n",WEXITSTATUS(val));//提取退出码
}
}
for(int i=0;i<n;i++)
{
printf("s=%s\n",s);
sleep(1);
}
exit(3);
}
结果
stu@stu-virtual-machine:~/Linux/day08$ ./tests=childs=childs=childexit_code=3s=parents=parents=parents=parents=parents=parents=parents=parents=parents=parent
父进程先于子进程结束不是僵死进程
因为子进程在父进程结束后被init接收,init pid=1
test.c
#include
#include
#include
#include
#include
#include
int main()
{
int n=0;
char*s=NULL;
pid_t pid=fork();
assert(pid!=-1);
if(pid==0)
{
n=7;
s="child";
}
else
{
n=3;
s="parent";
/*
int val=0;
wait(&val);
if(WIFEXITED(val))//判断程序正常结束
{
printf("exit_code=%d\n",WEXITSTATUS(val));//提取退出码
}
*/
}
for(int i=0;i<n;i++)
{
printf("s=%s,pid=%d,ppid=%d\n",s,getpid(),getppid());
sleep(1);
}
exit(3);
}
结果(以前init接管,ppid=1,现在不一定)
stu@stu-virtual-machine:~/Linux/day08$ ./tests=parent,pid=3849,ppid=2550s=child,pid=3850,ppid=3849s=parent,pid=3849,ppid=2550s=child,pid=3850,ppid=3849s=child,pid=3850,ppid=3849s=parent,pid=3849,ppid=2550s=child,pid=3850,ppid=3849stu@stu-virtual-machine:~/Linux/day08$ s=child,pid=3850,ppid=1816s=child,pid=3850,ppid=1816s=child,pid=3850,ppid=1816
Linux open read write close 系统调用(在内核中实现)
C语言 fopen fread fwrite fclose 库函数(/usr/lib/c.so 在库中实现)
Windows 分 文本文件 和 二进制文件,Linux不区分
man 2 openman 2 readman 2 writeman 2 close
int open(const char* pathname, int flags);//用于打开一个已存在的文件int open(const char* pathname, int flags,mode_t mode);//用于新建一个文件,并设置访问权限
pathname:将要打开的文件路径和名称
flags : 打开标志,如 O_WRONLY 只写打开
O_RDONLY 只读打开
O_RDWR 读写方式打开
O_CREAT 文件不存在则创建
O_APPEND 文件末尾追加
O_TRUNC 清空文件,重新写入
mode: 权限 如:“0600”----读写4+2
返回值:为文件描述符
ssize_t read(int fd, void* buf, size_t count);
fd 对应打开的文件描述符
buf 存放数据的空间
count 计划一次从文件中读多少字节数据
返回值:为实际读到的字节数
ssize_t write(int fd, const void* buf,size_t count);
fd 对应打开的文件描述符
buf 存放待写入的数据
count 计划一次向文件中写多少数据
int close(int fd);
fd 要关闭的文件描述符
写
#include #include #include #include #include #include #include int main(){ int fd=open("file.txt",O_WRONLY|O_CREAT,0600); assert(fd!=-1); write(fd,"hello",5); close(fd);}
结果
stu@stu-virtual-machine:~/Linux/day08$ ./openstu@stu-virtual-machine:~/Linux/day08$ lsfile.txt main main.c open open.c test test.cstu@stu-virtual-machine:~/Linux/day08$ cat file.txthello stu@stu-virtual-machine:~/Linux/day08$
读
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd=open("file.txt",O_RDONLY);
assert(fd!=-1);
char buff[128]={0};
int n=read(fd,buff,127);//n==0,表示读到了文件末尾
//只读127防止溢出
printf("buff=%s\n",buff);
close(fd);
}
结果
stu@stu-virtual-machine:~/Linux/day08$ ./open
buff=hello
open.c
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fdr=open("1.jpg",O_RDONLY);
int fdw=open("5.jpg",O_WRONLY|O_CREAT,0600);
if(fdr==-1||fdw==-1)
{
return 0;
}
char buff[1024]={0};
int n=0;
while((n=read(fdr,buff,1024))>0)
{
write(fdw,buff,n);
}
close(fdr);
close(fdw);
}
结果
stu@stu-virtual-machine:~/Linux/day08$ ./open
stu@stu-virtual-machine:~/Linux/day08$ ls
5.jpg main open test
file.txt main.c open.c test.c
stu@stu-virtual-machine:~/Linux/day08$ ls -l
总用量 76
-rw------- 1 stu stu 0 11月 30 17:53 5.jpg
-rw------- 1 stu stu 5 11月 30 17:34 file.txt
-rwxrwxr-x 1 stu stu 16736 11月 30 15:29 main
-rw-rw-r-- 1 stu stu 322 11月 30 15:29 main.c
-rwxrwxr-x 1 stu stu 16872 11月 30 17:52 open
-rw-rw-r-- 1 stu stu 743 11月 30 17:52 open.c
-rwxrwxr-x 1 stu stu 17016 11月 30 16:43 test
-rw-rw-r-- 1 stu stu 664 11月 30 16:43 test.c