Linux系统编程:进程控制1

🌍Linux系统编程2:进程控制

🌳fork函数
🍀作用与定义方式
作用:创建一个子进程。 定义:pid_t fork(void); 失败返回-1;成功返回0:① 父进程返回子进程的 ID(非负) ②子进程返回 0;pid_t类型表示进程 ID,但为了表示-1,它是有符号整型(0不是有效进程 ID,init最小为 1) ;

🍀 父子进程相同:

刚fork后。 data段、text段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式相同。

🍀父子进程不同:

.进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集不同。

🍀父子进程共享:
1、全局变量而言:读时共享、写时复制;
2、文件描述符 ;
3、 mmap映射区。

代码实现创建子进程在这里插入图片描述
运行结果:
在这里插入图片描述
🍀获取父子进程的两个函数

getpid();//获取当前进程ID
getppid();//获得父进程ID

编程实现:
在这里插入图片描述
运行结果:

在这里插入图片描述
观察运行结果:
观察子进程输出:子进程 pid=3140,父进程 pid=1630;
观察父进程输出:子进程pid=3140,自己进程pid=3139;父进程pid=2911。
出现的问题:从父进程返回的子进程和子进程的pid一样,子进程却说自己的父进程为pid=1630,父进程自己的pid=3139。
原因:父进程先死亡,子进程成为孤儿被收到了为pid=1630的孤儿院。

修改代码:给与父进程一个sleep(1)命令,子进程先于父进程死亡。
在这里插入图片描述
运行结果:
在这里插入图片描述
此时运行结果不再出现上述问题。

🍀循环创建多个子进程
一次 fork函数调用可以创建一个子进程。那么创建 N个子进程应该怎样实现呢?
简单想,for(i = 0; i < n; i++) { fork() } 即可。但这样创建的是 N个子进程吗?
在这里插入图片描述
从上图我们可以很清晰的看到,当 n为 3时候,循环创建了(2^n)-1个子进程,而不是 N的子进程。需要在循环的过程,保证子进程不再执行 fork ,因此当(fork() == 0)时,子进程应该立即 break;才正确。

编程实现:
在这里插入图片描述
运行结果:在这里插入图片描述
出现了问题:进程多了一个,而且不是按顺序来的。这里多出的一个,是父进程,因为父进程才有i=5跳出循环这一步。所以,对父进程进行判定并处理
修改代码如下:
在这里插入图片描述
运行结果:
在这里插入图片描述
现在还有两个问题:

  1. 一个就是包括父进程在内的所有进程不是按顺序出现,多运行几次,发现是随机序列出现的。这是要因为,对操作系统而言,这几个子进程几乎是同时出现的,它们和父进程一起争夺cpu,谁抢到,谁打印,所以出现顺序是随机的。
  2. 第二问题就是终端提示符混在了输出里,这个是因为,loop_fork(本程序名)是终端的子进程,一旦loop_fork执行完,终端就会打印提示符。就像之前没有子进程的程序,一旦执行完,就出现了终端提示符。这里也就是这个道理,loop_fork执行完了,终端提示符出现,然而loop_fork的子进程还没执行完,所以输出就混在一起了。解决方法如下让父进程加个sleep函数。让父进程在所有子进程结束后运行
    在这里插入图片描述
    .运行结果:在这里插入图片描述

🌳父子进程共享哪些内容
上面已经提到
1、父子进程相同:
刚fork后。 data段、text段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式。
父子进程不同:
进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集。
父子进程共享:
全局变量:读时共享、写时复制;
文件描述符; mmap映射区。

🌳父子进程gdb调试

设置父进程调试路径:set follow-fork-mode parent (默认)
设置子进程调试路径:set follow-fork-mode child

注意,一定要在fork函数调用之前设置才有效。

🌳exec函数族
fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种 exec函数以执行另一个程序。当进程调用一种 exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用 exec并不创建新进程,所以调用 exec前后该进程的 id并未改变。

将当前进程的.text、.data替换为所要加载的程序的.text、.data,然后让进程从新的.text第一条指令开始执行,但进程 ID不变,换核不换壳。

其实有六种以 exec开头的函数,统称 exec函数:
int execl(const char *path, const char *arg, …);
int execlp(const char *file, const char *arg, …);
int execle(const char *path, const char *arg, …, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);

🍀execlp函数
加载一个进程,借助 PATH环境变量
int execlp(const char *file, const char *arg, …); 成功:无返回;失败:-1
参数 1:要加载的程序的名字。该函数需要配合 PATH环境变量来使用,当 PATH中所有目录搜索后没有参数 1则出错返回。 该函数通常用来调用系统程序。如:ls、date、cp、cat等命令。

代码示例:通过execlp让子进程执行ls命令
在这里插入图片描述

运行结果
在这里插入图片描述
下面使用execl来让子程序调用自定义的程序。
int execl(const char *path, const char *arg, …)
这里要注意,和execlp不同的是,第一个参数是路径,不是文件名。这个路径用相对路径和绝对路径都行。
调用的代码如下

子进程要调用的程序:
在这里插入图片描述
exec程序:
在这里插入图片描述
运行结果:
在这里插入图片描述

注:以上内容均从总结于网上学习资源。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Finish_all

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值