目录
知识点1【进程的概述】(了解)
1、程序和进程的区别
2、单道程序、多道程序的理解
3、并行和并发(理解)
4、PCB进程控制块
5、进程的状态:
6、进程号
获取进程号:
获取父进程号:
获取进程组号:
案例:
知识点2【进程的创建 fork】(重要)
1、创建进程的函数fork
案例:
2、详细分析 父子进程关系
3、啥时候创建进程
4、fork创建父子进程资源是独立的
知识点3【回收进程的资源】(了解)
1、wait函数
2、获取子进程的退出状态
3、waitpid函数
知识点4【创建多进程】(重要)
1、知识点的引入
2、创建多进程
3、多进程的创建以及资源的回收(重要)
知识点5【特殊进程】(了解)
1、僵尸进程
2、孤儿进程
3、守护进程(精灵进程):是 Linux 中的后台服务进程。
4、终端
5、进程组
6、会话
7、创建会话的注意事项:
创建会话的函数:(重要)
8、创建守护进程流程
知识点6【vfork】(了解)
1、父子进程共享同一块空间
2、vfork创建子进程 会保证子进程先运行
知识点7【exec函数族】(了解)
1、execlp
2、execv
?3、execvp
4、vfork创建的子进程 如果调用exec函数族 父进程 会立即执行。
例程:实现 ps -A| grep bash
知识点1【进程的概述】(了解)
1、程序和进程的区别
????????程序:是存放在存储介质上的一个可执行文件,静态的,占磁盘空间。
????????进程:运行中的程序,动态的(创建、调度、消亡),占内存空间。
2、单道程序、多道程序的理解
????????单道程序:所有进程一个一个排队执行。若A阻塞,B只能等待,即使 CPU处于空闲状态。
????????多道程序:在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之下,相互穿插的运行
3、并行和并发(理解)
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。(多核)
并发(concurrency):单核,多任务,通过时间片快速替换,达到宏观同时执行的效果。微观(一个个指令执行)
4、PCB进程控制块
PCB 在内核空间 分配的维护进程相关的一个结构体task_struct
包含了:进程的状态,有就绪、运行、挂起、停止等状态。 进程切换时需要保存和恢复的一些CPU寄存器的拷贝。 描述虚拟地址空间的信息。 描述控制终端的信息。 当前工作目录(Current Working Directory)。 umask掩码。 文件描述符表,包含很多指向file结构体的指针。 和信号相关的信息。 用户id和组id。 会话(Session)和进程组。 进程可以使用的资源上限(Resource Limit)
5、进程的状态:
????????执行态、就绪态、等待态
????????等待态:执行条件不满足
????????就绪态:执行条件满足、但是未被CPU调度执行
????????执行态:正在被CPU调度执行
????????ps查看当前进程
????????ps -A查看所有用户态的进程
????????pstree 树状显示所有用户态进程
????????ps -aux 查看进程状态
ps常用选项
6、进程号
每个进程都由一个进程号来标识,其类型为 pid_t(整型),进程号的范围:0~32767
进程号总是唯一的,但进程号可以重用
????????PID:进程号
????????PPID:父进程号
????????PGID:进程组号
获取进程号:
getpid函数
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
功能:
??? 获取本进程号(PID)
参数:
??? 无
返回值:
??? 本进程号
获取父进程号:
getppid函数
#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);
功能:
??? 获取调用此函数的进程的父进程号(PPID)
参数:
??? 无
返回值:
??? 调用此函数的进程的父进程号(PPID)
获取进程组号:
getpgid函数
#include <sys/types.h>
#include <unistd.h>
pid_t getpgid(pid_t pid);
功能:
??? 获取进程组号(PGID)
参数:
??? pid:进程号
返回值:
??? 参数为 0 时返回当前进程组号,否则返回参数指定的进程的进程组号
示例代码:
案例:
#include?<stdio.h>
#include?<sys/types.h>
#include?<unistd.h>
int?main(int?argc,?char?const?*argv[])
{
????printf("进程号:%d\n",?getpid());
????printf("父进程号:%d\n",?getppid());
????printf("进程组号:%d\n",?getpgid(0));
????getchar();
????return?0;
}
如果一个进程 没有加入任何组 那么进程组号 和 进程号相同
知识点2【进程的创建 fork】(重要)
系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程。
1、创建进程的函数fork
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:
??? 用于从一个已存在的进程中创建一个新进程,新进程称为子进程,原进程称为父进程。
参数:
??? 无
返回值:
??? 成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为整型。
??? 失败:返回-1
案例:
#include?<sys/types.h>
#include?<unistd.h>
#include?<stdio.h>
int?main(int?argc,?char?const?*argv[])
{
????//创建进程
????pid_t?pid?=??fork();
????if(pid?==?0)//子进程
????{
????????printf("子进程号:%d\n",?getpid());
????????
????}
????else?if(pid?>?0)//父进程
????{
????????//pid为子进程的ID
????????printf("父进程号:%d?pid=%d\n",?getpid(),?pid);
????}
????getchar();
????return?0;
}
2、详细分析 父子进程关系
fork创建的进程,子进程 复制 父进程的资源 父子进程完全独立运行
(其实是读时共享、写时复制、后面会讲)
3、啥时候创建进程
当多个任务存在相互阻塞时 需要创建多进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
pid_t pid = fork();
if(pid < 0){
perror("fork");
_exit(-1);
}
else if(pid == 0){ //子进程
int j = 0;
while(1){
printf("任务2 ----- j = %d\n", j++);
sleep(1);
}
}
else if(pid > 0){ //父进程
int i = 0;
while(1){
printf("任务1 ----- i = %d\n", i++);
sleep(1);
}
}
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
任务1 ----- i = 0
任务2 ----- j = 0
任务1 ----- i = 1
任务2 ----- j = 1
任务2 ----- j = 2
任务1 ----- i = 2
任务2 ----- j = 3
任务1 ----- i = 3
*/
4、fork创建父子进程资源是独立的
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
int num = 10;
pid_t pid = fork();
if(pid < 0){
perror("fork");
_exit(-1);
}
else if(pid == 0){ //子进程
sleep(3);
printf("子进程中的 num = %d\n", num);
}
else if(pid > 0){ //父进程
num = 100;
printf("父进程中的 num = %d\n", num);
}
getchar(); //阻塞一下
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
父进程中的 num = 100
子进程中的 num = 10
*/
读共享 写独立
1、早期
Linux 系统设计是fork()
后,拷??进程内容给?进程,这时数据不论是否写操作,数据都会存在两份,这种设计太浪费内存空间
2、当前Linux 系统设计是fork() 后,不会直接拷贝?进程内容给?进程,当??进程有?个进程对数据进?写操作,才会进行内容复制,然后对自己的那份内容写操作。
知识点3【回收进程的资源】(了解)
进程结束 都会自动回收所有资源(除PCB),一般来说子进程的PCB由父进程回收。
wait ????????waitpid
注意:一次wait或waitpid调用只能清理一个子进程,清理多个子进程应使用循环
默认 wait? 、waitpid都是阻塞
1、wait函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
功能:
??? 等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。
参数:
??? status : 子进程退出时的状态信息
返回值:
??? 成功:已经结束子进程的进程号
失败: -1
2、获取子进程的退出状态
WIFEXITED(status)? 如果子进程是正常终止的,取出的字段值非零。
WEXITSTATUS(status)? 返回子进程的退出状态,退出状态保存在status变量的8~16位
只有子进程 正常退出 才能取子进程退出的状态值。
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????pid_t?pid?=?fork();
????if(pid?==?0)//子进程
????{
????????int?i=0;
????????for(i=5;i>0;?i--)
????????{
????????????printf("子进程%d?生命时间%d秒\n",?getpid(),?i);
????????????sleep(1);
????????}
????????//显示调用进程结束
????????_exit(10);
????}
????else?if(pid?>?0)//父进程
????{
????????int?st;
????????printf("等待子进程%d退出\n",?pid);
????????pid_t?ret_pid?=?wait(&st);//阻塞
????????printf("子进程%d已经退出了\n",?ret_pid);
????????if(WIFEXITED(st))//子进程正常退出
????????{
????????????//取出子进程的状态值
????????????printf("子进程的状态值:%d\n",?WEXITSTATUS(st));
????????}
????}
????
????return?0;
}
3、waitpid函数
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int options);
参数1:pid
pid > 0? 等待进程 ID 等于 pid 的子进程。
????? pid = 0? 等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。
????? pid = -1 等待任一子进程,此时 waitpid 和 wait 作用一样。
????? pid < -1 等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值
参数2:status
????????status : 进程退出时的状态信息。和 wait() 用法一样
参数3:options
?????????0:同 wait(),阻塞父进程,等待子进程退出。
????????WNOHANG:没有任何已经结束的子进程,则立即返回。
????????WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到)
wait(NULL) == waitpid(-1, NULL, 0)
返回值:
waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:
??????? 1) 当正常返回的时候,waitpid() 返回收集到的已经回收子进程的进程号;
??????? 2) 如果设置了选项 WNOHANG,还有子进程存在,则返回 0;
??????? 3) 所有子进程都退出,则返回-1,
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????pid_t?pid?=?fork();
????if(pid?==?0)//子进程
????{
????????int?i=0;
????????for(i=5;i>0;?i--)
????????{
????????????printf("子进程%d?生命时间%d秒\n",?getpid(),?i);
????????????sleep(1);
????????}
????????//显示调用进程结束
????????_exit(10);
????}
????else?if(pid?>?0)//父进程
????{
????????int?st;
????????printf("等待子进程%d退出\n",?pid);
????????pid_t?ret_pid?=?waitpid(-1,?&st,?0);//阻塞
????????printf("子进程%d已经退出了\n",?ret_pid);
????????if(WIFEXITED(st))//子进程正常退出
????????{
????????????//取出子进程的状态值
????????????printf("子进程的状态值:%d\n",?WEXITSTATUS(st));
????????}
????}
????
????return?0;
}
知识点4【创建多进程】(重要)
1、知识点的引入
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????
????int?i=0;
????for(i=0;?i<2;?i++)
????{
????????pid_t?pid?=?fork();
????}
????
????while(1);
????
????return?0;
}
2、创建多进程
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????
????int?i=0;
????for(i=0;?i<2;?i++)
????{
????????pid_t?pid?=?fork();
????????if(pid?==?0)//防止子进程?创建新的子进程
????????????break;
????}
????
????while(1);
????
????return?0;
}
3、多进程的创建以及资源的回收(重要)
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????int?n?=?3;
????int?i=0;
????for(i=0;?i<n;?i++)
????{
????????pid_t?pid?=?fork();
????????if(pid?==?0)//防止子进程?创建新的子进程
????????????break;
????}
????if(i==0)//子进程1
????{
????????printf("子进程1:%d?存活10秒\n",?getpid());
????????sleep(10);
????????_exit(-1);
????}
????else?if(i==1)//子进程2
????{
????????printf("子进程2:%d?存活6秒\n",?getpid());
????????sleep(6);
????????_exit(-1);
????}
????else?if(i==2)//子进程3
????{
????????printf("子进程3:%d?存活3秒\n",?getpid());
????????sleep(3);
????????_exit(-1);
????}
????else?if(i==n)//父进程
????{???
????????printf("父进程:%d\n",?getpid());
????????//负责回收子进程资源
????????while(1)
????????{
????????????pid_t?pid?=?waitpid(-1,?NULL,?WNOHANG);
????????????if(pid?>?0)//某个子进程?退出
????????????{
????????????????printf("子进程%d退出了\n",?pid);
????????????}
????????????else?if(pid?==?0)//还有子进程
????????????{
????????????????continue;
????????????}
????????????else?if(pid?==?-1)//所有子进程都结束了
????????????{
????????????????break;
????????????}
????????}
????}
????
????return?0;
}
知识点5【特殊进程】(了解)
1、僵尸进程
????????子进程退出 父进程没有调用wait、waitpid回收子进程资源 这时子进程就会成为僵尸进程。(危害)
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????int?n?=?3;
????int?i=0;
????for(i=0;?i<n;?i++)
????{
????????pid_t?pid?=?fork();
????????if(pid?==?0)//防止子进程?创建新的子进程
????????????break;
????}
????if(i==0)//子进程1
????{
????????printf("子进程1:%d\n",?getpid());
????????_exit(-1);
????}
????else?if(i==1)//子进程2
????{
????????printf("子进程2:%d\n",?getpid());
????????_exit(-1);
????}
????else?if(i==2)//子进程3
????{
????????printf("子进程3:%d\n",?getpid());
????????_exit(-1);
????}
????else?if(i==n)//父进程
????{???
????????while(1);
????}
????
????return?0;
}
2、孤儿进程
????????父进程先结束 子进程为孤儿进程。孤儿进程 会被1号进程 接管 回收其资源。(没有危害)
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????int?n?=?3;
????int?i=0;
????for(i=0;?i<n;?i++)
????{
????????pid_t?pid?=?fork();
????????if(pid?==?0)//防止子进程?创建新的子进程
????????????break;
????}
????if(i==0)//子进程1
????{
????????printf("子进程1:%d\n",?getpid());
????????while(1);
????????_exit(-1);
????}
????else?if(i==1)//子进程2
????{
????????printf("子进程2:%d\n",?getpid());
????????while(1);
????????_exit(-1);
????}
????else?if(i==2)//子进程3
????{
????????printf("子进程3:%d\n",?getpid());
????????while(1);
????????_exit(-1);
????}
????else?if(i==n)//父进程
????{???
????????
????}
????
????return?0;
}
3、守护进程(精灵进程):是 Linux 中的后台服务进程。
????????独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。 守护进程是个特殊的孤儿进程。
4、终端
????????登录终端 会得到bash进程 ./a.out 由bash进程创建子进程运行。
????????如果终端关闭 那么所有属于当前终端的进程 都会关闭。
查看0、1、2所属的终端
#include <unistd.h>
char *ttyname(int fd);
功能:由文件描述符查出对应的文件名
参数:
??? fd:文件描述符
返回值:
??? 成功:终端名
??? 失败:NULL
5、进程组
????????得到进程组号:getpgid()
????????一个或多个进程的集合 就是进程组。每个进程组 都有一个进程组号。
????????PGID就是进程组的组号 是该进程组中的第一个进程的进程号。
????????如果一个进程的进程号 和 组号相等 那么这个进程就是 组长进程。
????????父进程 通过fork创建的子进程 父子进程默认为同一个组 组号是父进程号。
????????进程组中所有进程都退出了 进程组才结束。
6、会话
话是一个或多个进程组的集合。
一个会话可以有一个控制终端。
会话进程特点:进程号==进程组号==会话号 相等
#include <unistd.h>
pid_t getsid(pid_t pid);
功能:获取进程所属的会话ID
参数:
??? pid:进程号,pid为0表示查看当前进程session ID
返回值:
??? 成功:返回调用进程的会话ID
??? 失败:
7、创建会话的注意事项:
创建会话的流程:建立新会话时,先调用fork, 父进程终止,子进程调用setsid得到会话ID:
创建会话的函数:(重要)
1) setsid的调用进程不能是进程组组长,该进程变成新会话首进程
2) 该进程成为一个新进程组的组长进程
3) 新会话丢弃原有的控制终端,该会话没有控制终端
#include <unistd.h>
pid_t setsid(void);
功能:
??? 创建一个会话,并以自己的ID设置进程组ID,同时也是新会话的ID。调用了setsid函数的进程,既是新的会长,也是新的组长。
参数:无
返回值:
??? 成功:返回调用进程的会话ID
??? 失败:-1
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include<string.h>
int?main(int?argc,?char?const?*argv[])
{
????pid_t?pid=fork();
????if(pid?>?0)
????????_exit(-1);
????else?if(pid?==?0)
????{
????????//将子进程设置一个会话
????????setsid();
????????printf("pid=%d,?pgid=%d,?sid=%d\n",?getpid(),?getpgid(0),?getsid(0));
????????while(1);
????}
????return?0;
}
8、创建守护进程流程
1) 创建子进程,父进程退出(必须) 所有工作在子进程中进行形式上脱离了控制终端
2) 在子进程中创建新会话(必须) setsid()函数 使子进程完全独立出来,脱离控制
3) 改变当前目录为根目录(不是必须) chdir()函数 防止占用可卸载的文件系统 也可以换成其它路径
4) 重设文件权限掩码(不是必须) umask()函数 防止继承的文件创建屏蔽字拒绝某些权限 增加守护进程灵活性
5) 关闭文件描述符(不是必须) 继承的打开文件不会用到,浪费系统资源,无法卸载
6) 开始执行守护进程核心工作(必须) 守护进程退出处理程序模型
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include?<string.h>
int?main(int?argc,?char?const?*argv[])
{
????//1、创建子进程
????pid_t?pid?=?fork();
????if(pid?>?0)
????????_exit(-1);
????//2、在子进程中创建会话
????setsid();
????//3、更改目录
????chdir("/");
????//4、重置掩码
????umask(0002);
????//5、关闭终端文件描述符
????close(0);
????close(1);
????close(2);
????//6、守护进程?和兴功能代码
????while(1)
????{
????????;
????}
????
????return?0;
}
知识点6【vfork】(了解)
vfork函数:创建一个新进程
pid_t vfork(void)
功能:
vfork函数和fork函数一样都是在已有的进程中创建一个新的进程
返回值:
创建子进程成功,则在子进程中返回0,父进程中返回子进程ID
fork创建的子进程 和 父进程 拥有独立的空间。
vfork创建的子进程 共享父进程 的空间。
1、父子进程共享同一块空间
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include?<string.h>
int?main(int?argc,?char?const?*argv[])
{
????int?num=?10;
????pid_t?pid?=?vfork();
????if(pid?==?0)//子进程
????{
????????num?=?200;
????????_exit(-1);
????}
????else?if(pid?>?0)//父进程
????{
????????printf("父进程的num=%d\n",?num);
????}
????
????return?0;
}
//父进程的num=200
2、vfork创建子进程 会保证子进程先运行
只有子进程(exit _exit)退出,或调用exec函数族时(后面会讲) 父进程才能运行
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
pid_t pid = vfork();
if(pid == 0){ //子进程
int i = 0;
for(i=5; i>0; i--){
sleep(1);
printf("子进程中的 i = %d\n", i);
}
_exit(-1);
}
else if(pid > 0){ //父进程
int i = 0;
for(i=5; i>0; i--){
sleep(1);
printf("父进程中的 i = %d\n", i);
}
_exit(-1);
}
getchar(); //阻塞一下
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
子进程中的 i = 5
子进程中的 i = 4
子进程中的 i = 3
子进程中的 i = 2
子进程中的 i = 1
父进程中的 i = 5
父进程中的 i = 4
父进程中的 i = 3
父进程中的 i = 2
父进程中的 i = 1
*/
知识点7【exec函数族】(了解)
exec函数族:在当前进程 切换运行另外的程序
exec函数族: 是多个函数的统称
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, .../* (char? *) NULL */);
int execlp(const char *file,cconst char *arg, ... /* (char? *) NULL */);
int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
int execve(const char *filename, char *const argv[], char *const envp[]);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
printf("当前进程\n");
execl("/bin/ls", "ls", "-ahl", NULL);
printf("其他程序运行后,看是否调用当前行\n");
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
当前进程
总用量 468K
drwxrwxr-x 2 brightsky brightsky 4.0K 7月 4 22:54 .
drwxrwxr-x 14 brightsky brightsky 4.0K 7月 2 20:00 ..
-rwxrwxr-x 1 brightsky brightsky 17K 7月 4 22:54 a.out
-rw-r--r-- 1 root root 0 7月 4 15:53 a.txt
-rw-rw-r-- 1 brightsky brightsky 4.0K 7月 2 22:53 c00.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 09:54 c01.c
-rw-rw-r-- 1 brightsky brightsky 5.8K 7月 3 11:59 c02.c
-rw-rw-r-- 1 brightsky brightsky 1006 7月 3 14:22 c03.c
-rw-rw-r-- 1 brightsky brightsky 461 7月 3 14:38 c04.c
-rw-rw-r-- 1 brightsky brightsky 344 7月 3 15:15 c05.c
-rw-rw-r-- 1 brightsky brightsky 4.2K 7月 3 18:49 c06.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 19:46 c07.c
-rw-rw-r-- 1 brightsky brightsky 539 7月 3 21:35 c08.c
-rw-rw-r-- 1 brightsky brightsky 3.5K 7月 4 21:07 c10.c
-rw-rw-r-- 1 brightsky brightsky 528 7月 4 22:54 c11.c
-rw------- 1 brightsky brightsky 380K 7月 3 11:53 core
-rw-rw-r-- 1 brightsky brightsky 11 7月 3 21:35 c.txt
-rwxrw-r-- 1 brightsky brightsky 418 7月 4 15:20 shell00.sh
*/
一个进程调用exec后,除了进程ID,进程还保留了下列特征不变: 父进程号 进程组号 控制终端 根目录 当前工作目录 进程信号屏蔽集 未处理信号 当然也会继承已经打开的文件描述符 标准输入输出和错误等
1、execlp
int execlp(const char *file,cconst char *arg, ... /* (char? *) NULL */);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
//启动其他程序
//execl("/bin/ls", "ls", "-ahl", NULL);
execlp("ls", "ls", "-ahl", NULL);
printf("其他程序运行后,看是否调用当前行\n");
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
总用量 468K
drwxrwxr-x 2 brightsky brightsky 4.0K 7月 4 22:54 .
drwxrwxr-x 14 brightsky brightsky 4.0K 7月 2 20:00 ..
-rwxrwxr-x 1 brightsky brightsky 17K 7月 4 22:54 a.out
-rw-r--r-- 1 root root 0 7月 4 15:53 a.txt
-rw-rw-r-- 1 brightsky brightsky 4.0K 7月 2 22:53 c00.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 09:54 c01.c
-rw-rw-r-- 1 brightsky brightsky 5.8K 7月 3 11:59 c02.c
-rw-rw-r-- 1 brightsky brightsky 1006 7月 3 14:22 c03.c
-rw-rw-r-- 1 brightsky brightsky 461 7月 3 14:38 c04.c
-rw-rw-r-- 1 brightsky brightsky 344 7月 3 15:15 c05.c
-rw-rw-r-- 1 brightsky brightsky 4.2K 7月 3 18:49 c06.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 19:46 c07.c
-rw-rw-r-- 1 brightsky brightsky 539 7月 3 21:35 c08.c
-rw-rw-r-- 1 brightsky brightsky 3.5K 7月 4 21:07 c10.c
-rw-rw-r-- 1 brightsky brightsky 528 7月 4 22:54 c11.c
-rw------- 1 brightsky brightsky 380K 7月 3 11:53 core
-rw-rw-r-- 1 brightsky brightsky 11 7月 3 21:35 c.txt
-rwxrw-r-- 1 brightsky brightsky 418 7月 4 15:20 shell00.sh
*/
2、execv
int execv(const char *path, char *const argv[]);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
//启动其他程序
//execl("/bin/ls", "ls", "-ahl", NULL);
//execlp("ls", "ls", "-ahl", NULL);
char *buf[] = {"ls", "-alh", NULL};
execv("/bin/ls", buf);
printf("其他程序运行后,看是否调用当前行\n");
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
总用量 468K
drwxrwxr-x 2 brightsky brightsky 4.0K 7月 4 22:54 .
drwxrwxr-x 14 brightsky brightsky 4.0K 7月 2 20:00 ..
-rwxrwxr-x 1 brightsky brightsky 17K 7月 4 22:54 a.out
-rw-r--r-- 1 root root 0 7月 4 15:53 a.txt
-rw-rw-r-- 1 brightsky brightsky 4.0K 7月 2 22:53 c00.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 09:54 c01.c
-rw-rw-r-- 1 brightsky brightsky 5.8K 7月 3 11:59 c02.c
-rw-rw-r-- 1 brightsky brightsky 1006 7月 3 14:22 c03.c
-rw-rw-r-- 1 brightsky brightsky 461 7月 3 14:38 c04.c
-rw-rw-r-- 1 brightsky brightsky 344 7月 3 15:15 c05.c
-rw-rw-r-- 1 brightsky brightsky 4.2K 7月 3 18:49 c06.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 19:46 c07.c
-rw-rw-r-- 1 brightsky brightsky 539 7月 3 21:35 c08.c
-rw-rw-r-- 1 brightsky brightsky 3.5K 7月 4 21:07 c10.c
-rw-rw-r-- 1 brightsky brightsky 528 7月 4 22:54 c11.c
-rw------- 1 brightsky brightsky 380K 7月 3 11:53 core
-rw-rw-r-- 1 brightsky brightsky 11 7月 3 21:35 c.txt
-rwxrw-r-- 1 brightsky brightsky 418 7月 4 15:20 shell00.sh
*/
?3、execvp
int execvp(const char *file, char *const argv[]);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char const *argv[]){
//启动其他程序
//execl("/bin/ls", "ls", "-ahl", NULL);
//execlp("ls", "ls", "-ahl", NULL);
//char *buf[] = {"ls", "-alh", NULL};
//execv("/bin/ls", buf);
char *buf[] = {"ls", "-alh", NULL};
execvp("ls", buf);
printf("其他程序运行后,看是否调用当前行\n");
return 0;
}
/**
brightsky@Bright-SKY:~/codes/blog$ ./a.out
总用量 468K
drwxrwxr-x 2 brightsky brightsky 4.0K 7月 4 22:54 .
drwxrwxr-x 14 brightsky brightsky 4.0K 7月 2 20:00 ..
-rwxrwxr-x 1 brightsky brightsky 17K 7月 4 22:54 a.out
-rw-r--r-- 1 root root 0 7月 4 15:53 a.txt
-rw-rw-r-- 1 brightsky brightsky 4.0K 7月 2 22:53 c00.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 09:54 c01.c
-rw-rw-r-- 1 brightsky brightsky 5.8K 7月 3 11:59 c02.c
-rw-rw-r-- 1 brightsky brightsky 1006 7月 3 14:22 c03.c
-rw-rw-r-- 1 brightsky brightsky 461 7月 3 14:38 c04.c
-rw-rw-r-- 1 brightsky brightsky 344 7月 3 15:15 c05.c
-rw-rw-r-- 1 brightsky brightsky 4.2K 7月 3 18:49 c06.c
-rw-rw-r-- 1 brightsky brightsky 1.6K 7月 3 19:46 c07.c
-rw-rw-r-- 1 brightsky brightsky 539 7月 3 21:35 c08.c
-rw-rw-r-- 1 brightsky brightsky 3.5K 7月 4 21:07 c10.c
-rw-rw-r-- 1 brightsky brightsky 528 7月 4 22:54 c11.c
-rw------- 1 brightsky brightsky 380K 7月 3 11:53 core
-rw-rw-r-- 1 brightsky brightsky 11 7月 3 21:35 c.txt
-rwxrw-r-- 1 brightsky brightsky 418 7月 4 15:20 shell00.sh
*/
4、vfork创建的子进程 如果调用exec函数族 父进程 会立即执行。
#include?<stdio.h>
#include?<sys/types.h>
#include?<sys/wait.h>
#include?<unistd.h>
#include?<string.h>
int?main(int?argc,?char?const?*argv[])
{
????pid_t?pid?=?vfork();
????if(pid?==?0)//子进程
????{
????????int?i=0;
????????for(i=5;i>0;i--)
????????{
????????????printf("子进程%d?i=%d\n",?getpid(),?i);
????????????if(i==3)
????????????{
????????????????//exec启动新的程序
????????????????execl("/bin/ls",?"ls","-alh",?NULL);
????????????}
??????????
????????????sleep(1);
????????}
????????_exit(-1);
????}
????else?if(pid?>?0)//父进程
????{
????????int?i=0;
????????for(i=5;i>0;i--)
????????{
????????????printf("父进程%d?i=%d\n",?getpid(),?i);
????????????sleep(1);
????????}
????}
????
????return?0;
}
例程:实现 ps -A| grep bash
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "string.h"
#include "fcntl.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/wait.h"
int main(int argc, char const *argv[])
{
int fd[2];
pipe(fd);
pid_t pid = fork();
if(pid < 0)
{
perror("fail to fork\n");
_exit(1);
}
else if (pid == 0)
{
close(fd[1]);
dup2(fd[0],0);
execlp("grep", "grep", "bash", NULL);
close(fd[0]);
_exit(1);
}
else if (pid > 0)
{
close(fd[0]);
dup2(fd[1],1);
execlp("ps", "ps", "-A", NULL);
wait(NULL);
close(fd[1]);
_exit(1);
}
return 0;
}
|