Linux七(进程复制与替换)


添加内容:
具体bash 命令解释器(一个终端运行一bash)
链接的时候会把函数的地址确定下来
用Vi写好的程序在I/O设备上(硬盘),运行时在内存中

1.printf函数的输出问题(printf有一个缓冲区)

printf函数并不会直接讲数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。
1)缓冲区满
2)强制刷新缓冲区 fflush
3)程序结束时
有缓冲区的优势:降低内核消耗,不用重复执行打印操作,等需要打印的数据在缓冲区放满之后,进行一次打印即可。如果没有放满,到程序结束时,先刷缓冲区,也可打印
在这里插入图片描述
2.主函数的参数

int main(int argc,char*argv[],char*envp[])

参数个数 参数列表 环境变量
在这里插入图片描述
“hello” “abc” "123"是传给主函数的参数
在这里插入图片描述
增加环境变量
在这里插入图片描述
附:
在这里插入图片描述

在这里插入图片描述
printf执行结束后,数据存在buff中,暂时不打印。write直接打印B,fork将buff中的数据复制一次,进程结束全部打印

2.复制进程fork

2.1 fork方法
pid_t fork(void);
fork函数会新生成一个进程,调用fork函数的进程为父进程,新生成的进程为子进程。在父进程中返回子进程的pid,在子进程中返回0(执行fork之后强制为0),失败返回-1。
在这里插入图片描述
要注意的几个问题:
1)父子进程并发运行的理解
2)逻辑地址 物理地址
3)写时拷贝技术
详解:https://www.csdn.net/
2.2 fork练习
1.
在这里插入图片描述
在这里插入图片描述
2.无\n(数据先存放在缓冲区中,程序结束时一次打印)
在这里插入图片描述
在这里插入图片描述
3.
在这里插入图片描述

在这里插入图片描述
父进程复制后,子进程不会再执行父进程执行过的语句

3.僵死进程及处理方法

僵死进程:子进程先于父进程结束,父进程没有调用wait获取子进程的退出码。
如果父进程先于子进程结束,则子进程会被1号进程接受,不会变成僵死进程
僵死进程数量多的话,会占用内核的id
当进程结束的时候,先将实体占的内存释放掉,再释放PCB,进程彻底消失
产生僵死进程的代码:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
int main(int argc,char* argv[],char* envp[])
{
char*s=NULL;
int n=0;
pid_t pid=fork();
assert(pid!=-1)
if(pid==0)
{
s="child";
n=4;
}
else
{
s="parent"
n=10;
}
int i=0;
for(;i<n;i++)
{
printf("pid=%d,s=%s\n",getpid(),s);
sleep(1);
}
exit(0)
}

在这里插入图片描述
处理僵死进程:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
int main(int argc,char* argv[],char* envp[])
{
char*s=NULL;
int n=0;
pid_t pid=fork();
assert(pid!=-1)
if(pid==0)
{
s="child";
n=4;
}
else
{
s="parent"
n=10;
int val=0;
int id=wait(&val);
if(WIFEXITED(val))
{
printf("id=%d,val=%d\n",id,WEXITSTATUS(val));
}
int i=0;
for(;i<n;i++)
{
printf("pid=%d,s=%s\n",getpid(),s);
sleep(1);
}
exit(3)
}

在这里插入图片描述

4.操作文件的系统调用

open read write close(系统调用)
linux 一切皆文件
man(帮助手册)1.命令 2.系统调用 3.库函数
man strlen
man fork
man ls
……都是系统调用
fopen fread fgets 都是函数
打开文件:二进制,文本
Linux不区分二进制和文本
5.1

 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
size_t read(int fd,void*buf,size_t count);
fd 对应打开的文件描述符
buf 存放数据的空间
count 计划一次从文件中读多少字节数据
返回值 为实际读到的字节数
size_t write(int fd,const void*buf,size_t count);
fd 对应打开的文件描述符
buf 存放待写入的数据
count 计划一次向文件中写入多少数据

打开文件:
int fd=open(“a.txt”,O_WRONL|0_CREAT,0600)
没有特殊权限:第一个数字为零
自己有读写权限:4+2=6
同组人没有权限:为0
other没有权限:为0
描述符是个整型数据
期望读到的和实际读到的数据不一定一样
期望可能读100个数据,实际返回的可能只有五个
写同上
在这里插入图片描述
1).打开文件
2).若成功,将打开的文件写入buff中
3).读buff中的文件
4).打印buff中的文件
5).若读到的值为0,说明已经读到文件末尾
在这里插入图片描述
5.2.每个进程都有自己的文件表
程序一旦启动,都会自动打开这三个文件:
标准输入:FILE* stdin
标准输出: stdout
标准错误输出: stderr
在这里插入图片描述

printf函数一次打印多个字母时,本质上是最后一次打印,但多次调用printf函数,前面的都存放在buff中。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
由于fork创建的子进程的PCB是拷贝父进程的,子进程的PCB中的文件表指向打开文件的指针只是拷贝了父进程PCB中的值,所以父子进程会共享父进程fork之前打开的所有文件描述符。如下图所示:在这里插入图片描述
如果要父子进程互补影响,则先进行复制,再打开文件,此时父子进程都有一个struct file,偏移量不共享(情况较少)
5.3 练习:写一个程序完成对一个普通文件的复制
在这里插入图片描述
在这里插入图片描述
5.4 库函数和系统调用的区别:系统调用的实现在内核中,属于内核空间,而库函数的实现在函数库中,属于用户空间。
详解链接: https://www.csdn.net/.

5.进程替换

1)execl
在这里插入图片描述第一个PS是命令名称,第二个PS是当前程序的名字,最后一个参数必须为空指针
在这里插入图片描述
详解链接1:https://www.csdn.net/
链接2:https://www.csdn.net/
替换进程:exec系列
进程替换之后,PCB不变
在这里插入图片描述
在这里插入图片描述
6.命令解释器(bash)替换步骤
bash fork+exec()
在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值