Linux 进程(2)

进程的回收
1.wait

原型

pid_t wait(int *status);

功能:该函数可以阻塞等待任意子进程退出
      并回收该进程的状态。
  一般用于父进程回收子进程状态。

参数:status 进程退出时候的状态
  如果不关心其退出状态一般用NULL表示
  如果要回收进程退出状态,则用WEXITSTATUS回收。

返回值:

        成功时,wait返回终止子进程的PID。

        失败时,返回-1,并设置errno来指示错误。

关于子进程状态的一些宏定义:

1.WIFEXITED(status)  是不是正常结束,如果返回非零值,则表示子进程正常结束了它的main函数,或者调用了exit()函数。
2.WEXITSTATUS(status)  为真时,使用这个宏来获取子进程的退出状态码。状态码是由main函数的返回值或者exit()函数的参数决定的。
3.WIFSIGNALED(status) 检查子进程是否是因为接收到信号而终止的。如果返回非零值,则表示子进程是因为信号而终止。    
4.WTERMSIG(status) 为真时,使用这个宏来获取导致子进程终止的信号编号。

5.WIFSTOPPED(status): 检查子进程是否因为接收到SIGSTOPSIGTSTPSIGTTINSIGTTOU信号而停止。如果返回非零值,则表示子进程已经停止。

6.WSTOPSIG(status): 当WIFSTOPPED(status)为真时,使用这个宏来获取导致子进程停止的信号编号。

7.WIFCONTINUED(status): 检查子进程是否已经从停止(stopped)状态继续执行。如果返回非零值,则表示子进程已经继续。

举例:


int a=20;
int main(int argc, const char *argv[])
{
	pid_t ret =fork();
	if(ret>0)
	{
		//
		printf("father is %d   pid= %d,ppid= %d \n",a,getpid(),getppid());
		wait(NULL);
		printf("after wait\n");
		sleep(5);

	}
	else if(0==ret)
	{
		printf("child = %d pid:%d ppid:%d",a,getpid(),getppid());
		sleep(3);
		printf("child terminal\n");
		exit(1);
	}
	else
	{
		perror("fork");
		return 1;
	}
	printf("a:%d  pid:%d",a,getpid());

	return 0;
}


利用宏定义,判断子进程的状态

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int a = 20;
int main(int argc, char *argv[])
{
    pid_t ret = fork();
    if(ret>0)
    {
        //father
            printf("father is %d   pid %d ,ppid:%d  \n",a,getpid(),getppid());
            int status;
            pid_t pid = wait(&status);
            if(WIFEXITED(status))// 代表子进程正常结束
            {
                //正常结束的子进程,才能获得退出值
                printf("child quit values %d\n",WEXITSTATUS(status));
            }
            if(WIFSIGNALED(status))//异常结束
            {
                printf("child unnormal signal num %d\n", WTERMSIG(status));
            }

            printf("after wait, %d\n",status);

    }
    else if(0 == ret)
    {
        //child
            printf("child a is %d pid:%d ppid:%d\n",a,getpid(),getppid());
            sleep(5);
            printf("child terminal\n");
            exit(50);
    }
    else 
    {
        perror("fork error\n");
        return 1;
    }
    printf("a is %d pid:%d\n",a,getpid());
    return 0;
}

2.waitpid

原型

#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

参数说明:

  • pid: 子进程的PID。如果设置为 -1,则表示等待任一子进程,这与 wait 函数的行为相同。
  • status: 指向整数的指针,用于接收子进程的状态信息。如果不需要状态信息,可以传递 NULL
  • options: 指定等待行为的选项,常用的选项有:
    • WNOHANG: 如果子进程尚未终止,调用立即返回,而不是挂起等待。
    • 0:  表示回收过程会阻塞等待

返回值:

  • 成功时,返回子进程的PID。
  • 如果子进程尚未终止(使用了 WNOHANG 选项),返回 0。
  • 失败时,返回 -1,并设置 errno 以指示错误

练习:

设计一个多进程程序,用waitpid函数指定回收
其中的某个进程资源并将其状态打印输出。
其他的进程都以非阻塞方式进行资源回收。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
    int i = 0 ;
    pid_t ret[5]={0};
    printf("father  pid %d ,ppid:%d  \n",getpid(),getppid());
    for(i = 0 ;i<5;i++)
    {
        ret[i] = fork();
        if(ret[i]>0)
        {
            //father

        }
        else if(0 == ret[i])
        {
            //child
            printf("child  pid:%d ppid:%d\n",getpid(),getppid());
            sleep(rand()%5);
            exit(1);
        }
        else 
        {
            perror("fork error\n");
            return 1;
        }
    }
    int status;
    while(1)
    {
        pid_t pid = waitpid(ret[2],&status, WNOHANG);
        if(ret[2] == pid)
        {
            if(WIFEXITED(status))// 代表子进程正常结束
            {
                //正常结束的子进程,才能获得退出值
                printf("child quit values %d\n",WEXITSTATUS(status));
            }
            if(WIFSIGNALED(status))//异常结束
            {
                printf("child unnormal signal num %d\n", WTERMSIG(status));
            }
            printf("father recycle success, pid :%d\n",pid);
            break;
        }
        else if(0 == pid)
        {
            printf("子进程未结束,稍后在试\n");
            //usleep(1000);
            sleep(1);
        }

    }
    printf("after wait, %d\n",status);
    return 0;
}

exec

exec函数族在 C 语言中用于在当前进程的上下文中执行一个新的程序。exec 函数不会创建新的进程,而是替换当前进程的映像为新程序的映像。这意味着进程的PID保持不变,但是执行的程序完全改变。

exec族函数

  1. execl(const char *path, const char *arg0, ...):

            加载并执行由 path 指定的程序,arg0 是传递给新程序的主参数,后面可以跟随其他参数,以 NULL 结尾。
  2. execv(const char *path, char *const argv[]):

              加载并执行由 path 指定的程序,argv 是一个以 NULL 结尾的参数数组。
  3. execle(const char *path, const char *arg0, ..., char *const envp[]):

               与 execl 类似,但允许指定一个新的环境指针数组 envp,替换当前环境。
  4. execve(const char *path, char *const argv[], char *const envp[]):

               加载并执行由 path 指定的程序,argv 是参数数组,envp 是环境变量数组。
  5. execlp(const char *file, const char *arg0, ...):

               与 execl 类似,但在 PATH 环境变量中搜索程序 file
  6. execvp(const char *file, char *const argv[]):

               与 execv 类似,但在 PATH 环境变量中搜索程序 file
  7. execvpe(const char *file, char *const argv[], char *const envp[]):

               与 execve 类似,但在 PATH 环境变量中搜索程序 file,并允许指定新的环境变量数组 envp

举例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    //  firefox www.baidu.com 
    //execl("/usr/bin/firefox","firefox","www.baidu.com",NULL);
    // env echo $PATH  ls -l --color=auto ll
    //execlp("ls","ls","-l","--color=auto",NULL);
    
    char *const args[]={"ls","-l","--color=auto",NULL};
    //execv("/bin/ls",args);//vector
    // path
    execvp(args[0],args);//vector+path
    printf("看见就错了\n");
    exit(1);
    return 0;


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    //  firefox www.baidu.com 
    //execl("./aaa","aaa","1","2","3",NULL);
    // env echo $PATH  ls -l --color=auto ll
    
    //execlp("./aaa","aaa","1","2","3",NULL);
    char *const args[]={"aaa","1","2","3",NULL};
    //execv("./aaa",args);//vector
    // path
    execvp("./aaa",args);//vector+patha

    //如果需要都能调用成功,第一个参数都传 路径+文件名
    printf("看见就错了\n");
    exit(1);
    return 0;
}

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值