进程创建方式与exec函数簇

本文深入探讨了进程管理技术,包括fork()和vfork()系统调用的原理与区别,以及exec函数族如何实现进程程序替换。同时介绍了这些系统调用在实际编程中的应用案例。

 

进程的两个基本元素:
1、程序代码;
2、与代码相关联的数据集
**********************************************************************************************************
一、要创建一个子进程可以执行fork()系统调用。
         
         返回值:成功的话,有两个返回值(子进程->0,父进程->子进程的 id);失败返回 -1.
子进程与父进程的关系:数据独立,代码共享。
子进程会得到父进程中数据段,栈段和堆区域的一份拷贝。子进程独立可以修改这些内存段(但这些都是当有进程要对这些区域里的数据进行修改时,拷贝才会发生)。但是文本段是父进程和子进程共享的内存段,不能被子进程修改。

fork成功后,父子进程的执行顺序是不确定的,是由内核的调度算法决定的。
fork的一个特性:父进程的所有打开文件描述符都被复制到子进程中。父子进程的每个相同的打开描述符共享一个文件表项

fork有下面两种用法:
1、父进程希望子进程执行自己的一个代码分支
2、fork成功后,调用exec函数簇,执行其它的代码(进程的程序替换)

fork调用失败的原因:
1、系统中有太多的进程
2、实际用户的进程数超过了限制
父子进程之间的区别 1. fork的返回值
 2. 进程ID 不同
 3. 具有不同的父进程ID
 4. 子进程的tms_utime tms_stime tms_cutimetms_ustime 均被设置为0
 5. 父进程设置的文件锁不会被子进程继承
 6. 子进程的未处理闹钟被清除
 7. 子进程的未处理信号集被设置为空集
**********************************************************************************************************
二、要创建一个子进程也可以执行vfork()系统调用。
       
该函数的特点:
(1)父子进程会共享同一地址空间
(2)vfork保证子进程先运行,它调用 exec或(exit)之后父进程才可能被调度运行
注意:子进程不能以 return 结束,否则会死循环(return可能会修改程序计数器,使它又指向main函数的入口地址)
**********************************************************************************************************
三、exec进程程序替换

当进程调用一种 exec函数时 ,该进程的用户空间代码和数 据完全被新程序替换 ,从新程序的启动例程开始执行。调用 exec不创建新进程 ,所以调用 exec前 后该进程的 id并未改变。
其实有六种以 exec开头的函数 ,统称 exec函数
#include <unistd.h>
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[]);
这些函数如果调用成功则加载新的程序从启动代码开始执行 ,不再返回 ,如果调用出错则返回-1, 所以 exec函数只有出错的返回值,而没有成功的返回值。


不带字母 p( 表示path) exec 函数 第一个参数必须是程序的相对路径或绝对路径 ,例如"/bin/ls" "./a.out",而不能 是 "ls" "a.out"。对于带字母 p的函数 : 如果参数中包含 /,将其视为路径名。 否则视为不带路径的程序名 , PATH环境变量的目录列表中搜索这个程序。

带有字母 l(表示 list) exec函数 要求将新程序的每个命令行参数都当作一个参数传给命令行参数的个数是可变的 ,因此函数原型中有 ...,...中的 最后一个可变参数应该是NULL, sentinel 的作用。

带有字母 v(表示 vector)的函数 ,则应该 先构造一个指向各参数的指针数 组 ,然后将该数组的首地址当作参数传给它 ,数组中的最后一个指针也应该是 NULL, 就像main 函数 的argv参数或者环境变量表一样。

对于以e(表示environment)结尾的exec函数,可以把一份新的环境变量表传给它,其他exec函数 仍使用当前的环境变量表执行新程序。
**********************************************************************************************************
四、进行进程程序替换函数的应用举例
(1)int execl(const char *path, const char *arg, ...);
          
          该程序的执行结果:父进程会输出:this is father process,子进程:会在 "/home/zhangdan/BIT_CLASS"下执行 "ls -al"命令
(2)int execlp(const char *file, const char *arg, ...); 
         该函数的使用与(1)类似,只是因为“p"的原因,有所改变。
          如要实现(1)的功能,则上述第11行的 "/bin/ls"可改为”ls"(不改也可以)。
(3)int execv(const char *path, char *const argv[]);
         
(4)int execvp(const char *file, char *const argv[]);
           该函数与(2)的修改方式一样,它是基于(3)可改变第一个参数。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值