进程(二)

vfork函数也可以创建进程

vfork与fork的区别:

  1. vfork直接使用父进程存储空间,不拷贝;
  2. vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。
// fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        pid_t pid;
        pid = fork();

        if(pid > 0)
        {
                while(1)
                {
                        printf("this is father pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }
        else if(pid == 0)
        {
                while(1)
                {
                        printf("this is child pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }

        return 0 ;

}
// vfork,只有子进程运行
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
        pid_t pid;
        int cnt = 0;
        pid = vfork();

        if(pid > 0)
        {
                while(1)
                {
                        printf("this is father pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }
        else if(pid == 0)
        {
                while(1)
                {
                        printf("this is child pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }

        return 0 ;

}
// 达到相应的条件后,调用exit退出子进程,程序执行父进程,注意使用exit退出
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid;
        int cnt = 0;
        pid = vfork();

        if(pid > 0)
        {
                while(1)
                {
                        printf("this is father pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }
        else if(pid == 0)
        {
                while(1)
                {
                        printf("this is child pid, pid = %d\n", getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3)
                        {
                                exit(0);
                        }
                }
        }

        return 0 ;

}

进程退出

  1. 正常退出

    Main函数调用return;

    进程调用exit(),标准C库;

    进程调用_exit()或者 _Exit(),属于系统调用

    补充:进程最后一个线程返回;最后一个线程调用pthread_exit

  2. 异常退出

    调用abort;

    当进程收到某些信号时,如ctrl+c;

    最后一个线程对取消(cancellation)请求做出响应。

不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。

对上述任意一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit,_exit, _Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数。在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状态(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得其终止状态。

父进程等待子进程退出

为何要等待子进程退出?看子进程有没有干完活,继续进行接下来的工作。

父进程等待子进程退出,并收集子进程的退出;若子进程退出状态不被收集,将会变成僵死进程(僵尸进程)

说明
WIFEXITED(status)若为正常终止子进程返回的状态,则为真。对于这种情况可执行WEXITSTATUS(status),取子进程传送给exit,_exit或 _Exit参数的低8位
WIFSIGNALED(status)若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WTERMSIG(status),取使子进程终止的信号编号。另外,有些实现定义宏WCOREDUMP(status),若已产生终止进程的core文件,则它返回真。
WIFSTOPPED(status)若为当前暂停子进程的返回状态,则为真。对于这种情况,可执行WSTOPSIG(status),取使子进程暂停的信号编号
WIFCONTINUED(status)若在作业控制暂停后已经继续的子进程返回了状态,则为真。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid;
        int cnt = 0;
        int status = 10;

        pid = fork();

        if(pid > 0)
        {
                wait(&status);
                printf("child exit, child status = %d\n", WEXITSTATUS(status));
                while(1)
                {
                        printf("this is father pid, pid = %d\n", getpid());
                        sleep(1);
                }
        }
        else if(pid == 0)
        {
                while(1)
                {
                        printf("this is child pid, pid = %d\n", getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 5)
                        {
                                exit(6);
                        }
                }
        }

        return 0 ;

}

相关函数

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

pid_t wait(int *status);

pid_t waitpid(pid_t pid, int *status, int options);
/*
pid == -1 等待任一进程。就这一方面而言,waitpid与wait等效
pid > 0 等待其进程ID与pid相等的子进程
pid == 0 等待其组ID等于调用进程组ID的任一子进程
pid < -1 等待其组ID等于pid绝对值的任一子进程
*/

int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

如果其所有子进程都还在运行,则阻塞。

如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

如果它没有任何子进程,则立即出错返回。

wait和waitpid的区别:wait使调用者阻塞,waitpid有一个选择,可以使调用者不阻塞。

孤儿进程:父进程如果不等待子进程退出,在子进程之前就结束自己的"生命",此时子进程叫做孤儿进程;Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
        pid_t pid;
        int cnt = 0;
        int status = 10;

        pid = fork();

        if(pid > 0)
        {
                printf("this is father pid, pid = %d\n", getpid());
        }
        else if(pid == 0)
        {
                while(1)
                {
                        printf("this is child pid, pid = %d, father pid = %d\n", getpid(), getppid());    //getppid父进程的pid
                        sleep(1);
                        cnt++;
                        if(cnt == 5)
                        {
                                exit(6);
                        }
                }
        }

        return 0 ;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用C语言编写的程序,满足题目中的要求: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> #define MAX_BUF_SIZE 1024 int main() { int fd1[2], fd2[2]; // 两个管道 pid_t pid1, pid2; // 进程ID if (pipe(fd1) < 0 || pipe(fd2) < 0) { perror("pipe error"); exit(EXIT_FAILURE); } // 创建进程一 pid1 = fork(); if (pid1 < 0) { perror("fork error"); exit(EXIT_FAILURE); } else if (pid1 == 0) { // 子进程一 close(fd1[0]); close(fd2[0]); close(fd2[1]); // 进程一不需要用到第个管道 int fd = open("data.txt", O_RDONLY); char buf[MAX_BUF_SIZE]; int len = read(fd, buf, MAX_BUF_SIZE); write(fd1[1], buf, len); close(fd1[1]); exit(EXIT_SUCCESS); } else { // 父进程 pid2 = fork(); if (pid2 < 0) { perror("fork error"); exit(EXIT_FAILURE); } else if (pid2 == 0) { // 子进程 close(fd1[1]); close(fd2[0]); int len; char buf[MAX_BUF_SIZE]; len = read(fd1[0], buf, MAX_BUF_SIZE); for (int i = 0; i < len; ++i) { if (buf[i] >= '0' && buf[i] <= '9') { buf[i] += 1; } } write(fd2[1], buf, len); close(fd2[1]); exit(EXIT_SUCCESS); } else { // 父进程 close(fd1[0]); close(fd1[1]); close(fd2[1]); int fd = open("result.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666); char buf[MAX_BUF_SIZE]; int len = read(fd2[0], buf, MAX_BUF_SIZE); write(fd, buf, len); close(fd2[0]); int status; waitpid(pid1, &status, 0); waitpid(pid2, &status, 0); exit(EXIT_SUCCESS); } } return 0; } ``` 以上代码中,我们首先定义了两个管道,然后创建了两个子进程,分别完成读取文件和写入文件的任务,中间的进程则进行了加1操作。 具体来说,进程一通过管道一将文件读取到缓冲区,然后写入管道一。进程从管道一读取数据,进行加1操作,并将结果写入管道进程三从管道读取数据,并将结果写入文件中。最后,父进程等待两个子进程结束,退出程序。 需要注意的是,在实际的编程中,应该对各种系统调用的返回值进行错误检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Luish Liu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值