Linux -- 多进程编程之 - 基础实现、孤儿进程

一、进程的创建

  在Linux中创建一个新进程的方法是使用 fork() 函数。

  fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程

  使用fork()函数得到的子进程父进程的一个复制品,它从父进程处继承了整个进程的 地址空间,包括进程上下文代码段进程堆栈内存信息打开的文件描述符信号处理函数进程优先级进程组号当前工作目录根目录资源限制控制终端等。

  子进程所独有的只有它的进程号资源使用计时器等。

  因为子进程几乎是父进程的完全复制,所以父子两个进程会运行同一个程序。因此需要用一种方式来区分它们,并使它们照此运行,否则,这两个进程只能做相同的事。

  父子进程一个很重要的区别是:fork()返回值不同

  父进程中的返回值是子进程的进程号,而子进程中返回0。可以通过返回值来判定该进程是父进程还是子进程

注意:
  子进程没有执行fork()函数,而是从fork()函数调用的下一条语句开始执行。PID不同

  1、fork()函数的原型如下所示。

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

pid_t fork(void);

功能:
  以精确复制父进程的方式,创建新的子进程
返回:
  成功:父进程返回子进程PID, 子进程返回0
  失败:父进程返回-1,没有子进程

  2、获取PID以及父进程PID的函数的原型如下所示。

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

pid_t getpid(void);
	功能:获取当前进程的PID
pid_t getppid(void);
	功能:获取当前进程父进程的PID

  3、进程创建的程序示例如下所示。

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

int main(int argc, const char *argv[])
{
    int x = 0;
    /* 定义进程PID记录的变量 */
    pid_t pid = 0;
    /* 输出调试语句 */
    printf("fork() function test!\n");

    /* 调用fork()函数创建进程 */
    pid = fork();
    /* 函数返回值判断 */
    if (pid == -1) /* 返回错误 */
    {
        perror("fork error");
        return -1;
    }
    else if (pid == 0) /* 子进程 */
    {
        x = 10;
        printf("I'm child, pid = %d, &x = %p, x = %d\n", pid, &x, x);
        /* 子进程 */
        printf("my PID = %d, my parent PID = %d\n", getpid(), getppid());
    }
    else /* 父进程 */
    {
        sleep(1); /* 延时片刻,保证子进程先运行 */
        printf("I'm parent, pid = %d, &x = %p, x = %d\n", pid, &x, x);
        /* 父进程 */
        printf("return PID = %d, parent pid = %d\n", pid, getpid());
    }

    sleep(1);

    return 0;
}

  编译上述程序并进程运行之后,显示效果下图1.1所示。

图1.1 测试程序运行效果

  关于进程的退出操作,可以参考博文:Linux – exit()函数、_exit()函数、return的说明与使用

二、孤儿进程产生与处理

  孤儿进程:子进程本身处于运行状态,但是其父进程提前结束,此子进程被称为孤儿进程。

  孤儿进程 将被 init 进程(进程号为 1 )所收养,并由 init 进程对它们完成状态收集工作,因此孤儿进程并不会有什么危害。

孤儿进程会被1号进程收养,并最终由1号进程回收。不论子进程处于 运行状态(R)、休眠状态(S)、僵死状态(Z)、停止状态(T)都可被收养。

  下面用一个简单的程序显示一下孤儿进程的状态变化。

#include <stdio.h>
#include <stdlib.h> /* exit    */
#include <unistd.h> /* getpid等 */

int main(int argc, const char *argv[])
{
    /* 定义进程PID记录的变量 */
    pid_t pid = 0;

    /* 输出调试语句 */
    printf("Orphan process test!\n");

    /* 调用fork()函数创建进程 */
    pid = fork();
    /* 函数返回值判断 */
    if (pid == -1) /* 返回错误 */
    {
        perror("fork error");
        return -1;
    }
    else if (pid == 0) /* 子进程 */
    {
        unsigned long n = 0, m = 0;
        /* 子进程 */
        printf("I'm child, my PID = %d, my parent PID = %d\n", getpid(), getppid());

        /* 子进程延时片刻,保持子进程在父进程后面结束 */
        sleep(10);

        /* 调用函数退出子进程 */
        exit(EXIT_SUCCESS);
    }
    else /* 父进程 */
    {
        /* 延时片刻,保证子进程先运行 */
        usleep(20);

        /* 父进程延时片刻 */
        printf("Parent sleep(5) ...\n");
        sleep(5);

        printf("I'm parent, return PID = %d, my pid = %d\n", pid, getpid());
        /* 调用函数退出父进程 */
        exit(EXIT_SUCCESS);
    }

    return 0;
}

  编译上述程序并进程运行之后,显示效果下图2.1所示。

图2.1 测试程序运行效果

  此时在另外一个终端可以查看当前进程的状态。使用指令ps -ajx 查看,显示效果下图2.2所示。

图2.2 测试程序运行效果

  由上图可以看出来,在父进程退出之后,子进程的 PPID 变为了 1,也就是其父进程变为了 PPID 变为了 init 进程。

  
  好啦,废话不多说,总结写作不易,如果你喜欢这篇文章或者对你有用,请动动你发财的小手手帮忙点个赞,当然 关注一波 那就更好了,就到这儿了,么么哒(*  ̄3)(ε ̄ *)。

上一篇:Linux – 多任务机制(任务、进程、线程)介绍
下一篇:Linux – 多进程编程之 - 僵尸进程

  • 17
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

青椒*^_^*凤爪爪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值