exec函数族,
exit()进程退出。
特殊进程(孤儿,僵尸进程),
wait函数和waitpid函数。
exec函数族:
一个进程调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序代码,废弃原有数据段和堆栈段,并为新程序分配新数据段与堆栈段,
包含的函数如下:
//2022.5.12
#include
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)当参数是path,传入的为路径名;当参数是file,传入的可执行文件名;
(2)可以将exec函数族分为execl和execv两类:
execl类:函数将以列举的形式传入参数,由于参数列表的长度不定,所以要用哨兵NULL表示列举结束;
execv类:函数将以参数向量表传递参数,char * argv[]的形式传递文件执行时使用的参数,数组中最后一个参数为NULL;
(3)如果没有参数char * const envp[],则采用默认环境变量;如果有,则用传入的参数替换默认环境变量;
代码案例:
//2022.5.11 郭裕平
#include
#include
#include
int main(){
pid_t pid;
pid=fork();//创建进程
if(pid==-1){
perror("分叉错误");
exit(-1);
}//0f if
else if(pid>1){
printf("父进程:pid=%d\n",getpid());
}
else if(pid==0){
printf("子进程:pid=%d\n",getpid());
//execl("/bin/ls","-a","-l","test_fork.c".NULL);
//execl("ls","-a","-l","test_fork.c".NULL);
char *arg[]={"-a","-l","test_fork.c",NULL};
execvp("ls",arg);
perror("错误执行器\n");
printf("子进程:pid=%d\n",getpid());
}
return 0;
}
进程退出:
Linux系统中进程的退出通过exit()函数实现。exit()函数存在于系统函数库stdlib.h中,其声明如下:
#include
void exit(int status);
参数说明:
1)status:表示进程的退出状态,0表示正常退出,非0表示异常退出,一般用-1或1表示;
2)为了可读性,标准C定义了两个宏:EXIT_SUCCESS和EXIT_FAILURE
Linux系统中有一个与exit()函数非常相似的函数:_exit(),其声明如下:
#include
void _exit(int status);
区别:
特殊进程:
孤儿进程:父进程负责回收子进程,如果父进程在子进程退出之前退出,子进程就会变成孤儿进程,此时init进程将代替父进程完成子进程的回收工作;
僵尸进程:调用exit函数后,该进程不会马上消失,而是留下一个称为僵尸进程的数据结构。它几乎放弃进程退出前占用的所有内存,既没有可执行代码也不能被调度,只是在进程列表中保留一个位置,记载进程的退出状态等信息供父进程回收。若父进程没有回收子进程的代码,子进程将会一直处于僵尸态。
wait函数:
功能: 挂起进程,进程进入阻塞状态,直到子进程变为僵尸态,如果捕获到子进程的退出信 息 就会转为运行态,然后回收子进程资源并返回;若没有变为僵尸态的子进程,wait函数就 会让进程一直阻塞。若当前进程有多个子进程,只要捕获到一个变为僵尸态的子进程,wait 函数就会恢复执行态。
格式:
#include
pid_t wait(int *status);
参数:status是一个int * 类型的指针,用来保存子进程退出时的状态信息。但是通常我们只想消灭僵尸进程,不在意程序如何终止,因此一般将该参数设置为NULL。
返回值: 成功:返回子进程的进程id;
失败:返回-1,errno被设置为ECHILD。
代码案例:
#inlcude
#include
#include
#include
int main(){
pid_t tempPid, tempW;
tempPid = fork();
if(tempPid == -1){
perror("fork error");
exit(1;
}
else if(tempPid == 0){//child
sleep(3);
printf("Child process, pid = %d, ppid = %d\n", getpid(), getppid());
}
else{//parent
tempW = wait(NULL);
printf("Catched a child process, pid = %d, ppid = %d\n", tempW, getppid());
}//of if
printf("......finish......");
return 0;
}//of main
waitpid()函数:
功能:wait函数的缺点:当前进程有很多个子进程,wait函数无法保证所有子进程在父进程之前执行。可以应对 wait函数面临的缺点。可以等待指定的子进程,也可以在父进程不阻塞的情况下获取子进程的状态。
格式:
#include
pid_t waitpid(pid_t pid, int *status, int options);
参数说明:
pid:一般是进程的pid,也有可能是其他取值。进一步说明如下:
pid > 0:等待子进程(编号为pid)退出,若退出,函数返回;若未结束,则一直等待;
pid = 0:等待同一进程组的所有子进程退出,若某子进程加入了其他进程组,则waitpid不再关心它的状态;
pid = -1:waitpid函数退化为wait函数,阻塞等待并回收一个子进程;
pid < -1:等待指定进程组中的任何子进程,进程组的id等于pid的绝对值。
options: 提供控制选项,可以是一个常量,也可以是|连接的两个常量,选项如下:
WNOHANG:如果子进程没有终止,waitpid不会阻塞父进程,会立即返回;
WUNTRACED:如果子进程暂停执行,waitpid立即返回;
返回值说明:
成功:返回捕捉到的子进程id;
0:options = WNOHANG, waitpid发现没有已退出的子进程可回收;
-1:出错,errno被设置。
代码案例:1.父进程等待进程组中指定子进程,该进程不退出,则父进程一直阻塞。
#include
#include
#include
int main(){
pid_t tempPid, tempP, tempW;
tempPid= fork();
if (tempPid == -1){
perror("fork1 error");
exit(1);
}
else if (tempPid == 0){
sleep(5);
printf("First child process:pid=%d\n", getpid());
}
else {
int i;
tempP = tempPid;
for (i = 0; i < 3; i++){
if ((tempPid = fork()) == 0){
break;
}//of if
}//of for i
if (tempPid == -1){
perror("fork error");
exit(2);
}
else if (tempPid == 0){
printf("Child process:pid=%d\n", getpid());
exit(0);
}
else {
tempW = waitpid(tempP, NULL, 0);
if (tempW == tempP){
printf("Catch a child Process: pid=%d\n", tempW);
}
else{
printf("waitpid error\n");
}//of if
}//of if
}//of if
return 0;
}//of main
2.基于waitpid函数不断获取子进程的状态。
#include
#include
#include
int main() {
pid_t tempPid, tempW;
tempPid = fork();
if (tempPid == -1){
perror("fork error");
exit(1);
}
else if (tempPid == 0){
sleep(3);
printf("Child process:pid=%d\n", getpid());
exit(0);
}
else {
do{
tempW = waitpid(tempPid, NULL, WNOHANG);
if (tempW == 0){
printf("No child exited\n");
sleep(1);
}//of if
}
while (tempW == 0);
if (tempW == tempPid){
printf("Catch a Child process:pid=%d\n", w);
}
else{
printf("waitpid error\n");
}//of if
}//of if
return 0;
}//of main
2022.5.11--5.12
在多道程序环境中,进程是并行执行的,父进程与子进程可能没有交集,各自独立执行;但也有可能,子进程的执行结果是父进程的下一步操作的先决条件,此时父进程就必须等待子进程的执行。我们把异步环境下的一组并发进程因相互制约而互相发送消息、互相合作、互相等待,使得各进程按一定速度和顺序执行称为进程间的同步。
系统中进程的执行顺序是由内核决定的,使用这种方法很难做到对进程的精确控制。
系统的wait()与waitpid()函数来获取进程状态,实现进程同步。