linux系统编程 父进程和子进程fork

这里写图片描述

stack区和heap区分析

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
    printf("stack 区\n");
    int p = 7;
    printf("p = %X\n", &p);
    int x = 34;
    printf("x = %X\n", &x);

    printf("heap 区\n");
    char *w = malloc(34);
    if (!w)
        printf("malloc error\n");

    printf("w = %X\n", w);
    char *q = malloc(34);
    if (!q)
        printf("malloc error\n");

    printf("q = %X\n", q);

    if (w)
    {
        free(w);
        w = NULL;
    }

    if (q)
    {
        free(q);
        q = NULL;
    }
    return 0;
}

结构图

这里写图片描述

由上图可知 stack区 自上往下生长的, heap区是自下往上生长的

一,创建子进程fork函数

 pid_t fork(void);

创建成果返回打于0 ,失败返回 小于0

二,exec函数

这里写图片描述
exec函数族一般规律
exec函数一旦调用成功即执行新的程序,不返回。只有失败才返回,错误值-1。所以通常我们直接在exec函数调用后直接调用perror()和exit(),无需if判断。

  1. (list) 命令行参数列表
  2. p (path) 搜素file时使用path变量
  3. v (vector) 使用命令行参数数组
  4. e (environment) 使用环境变量数组,不使用进程原有的环境变量,设置新加载程序运行的环境变量
 int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const 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[]);

第一个参数是:命令
第二个参数是:命令的名称
m-n的参数 : 参数
最后一位数是:NULL

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    //pcb 进程控制块
    pid_t pid;

    //创建子进程
    pid = fork();

    if (pid < 0)
    {
        perror("fork error");
        exit(1);
    }
    else if (pid > 0) //父进程
    {
        printf("father fpid:%d, cpid:%d\n", getpid(), pid);
    }
    else if (pid == 0) //子进程操作
    {
        printf("child fpid:%d, cpid:%d\n", getppid(), getpid());
        //执行命令参数
        execle("./hello", "hello", "陈丽", "王蓉", NULL);
    }
    return 0;
}

效果图
这里写图片描述

三,进程孤儿进程和僵尸进程的解释

  1. 孤儿进程
    如果父进程先退出,子进程还没退出,则子进程成为孤儿进程,此时子进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)。
  2. 僵尸进程
    如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵尸(Zombie)进程(僵尸进程:只保留一些退出信息供父进程查询)。

四,wait函数和waitpid函数的使用

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
  1. wait函数是当个进程的使用
  2. waitpid是一个父进程和多个子进程的使用的
  3. waitpid使用的时候要注意第一个参数默认写 -1 是用来关闭子进程的所有的
/*************************************************************************
> File Name: 父子线程fork.c
> Author: songli
> QQ: 2734030745
> Mail: 15850774503@163.com
> CSDN: http://my.csdn.net/Poisx
> github: https://github.com/chensongpoixs
> Created Time: Thu 19 Oct 2017 10:30:31 PM CST
************************************************************************/

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



int main(int argc, char *argv[])
{
    // pcb 进程控制块 id 
    pid_t pid;

    int i, n = 4;
    for (i = 0; i < n; i++)
    {
        //创建子线程
        pid = fork();
        if (pid < 0) //异常的处理
        {
            perror("fork error");
            return -1;
        }
        else if (pid > 0) //父进程的pid
        {
            printf("father fpid:[%d], cpid:[%d]\n", getpid(), pid);
            //sleep(1);
        }
        else if (pid == 0) //子进程的pid
        {
            printf("child fpid:[%d], cpid:[%d]\n", getppid(), getpid());
            break; //防止子线程中创建子线程
        }
    }
    //==========================子线程的处理================================================
    if (i == 0)
    {
        printf("child id:[%d], cpid:[%d]\n", i, pid);
        //子线程关闭在执行中
        while(1)
            sleep(1);
    }
    if (i == 1)
    {
        printf("child id:[%d], cpid:[%d]\n", i, pid);
        //子线程关闭在执行中
        while(1)
            sleep(1);
    }
    if (i == 2)
    {
        printf("child id:[%d], cpid:[%d]\n", i, pid);
        //子线程关闭在执行中
        /*while(1)
        sleep(1);*/
        perror("no child ----");
        return 13;
    }

    if (i == 3)
    {
        printf("child id:[%d], cpid:[%d]\n", i, pid);
        //子线程关闭在执行中
        while(1)
            sleep(1);
    }
//=======================父进程的处理======================================================
if (i == 4)
{
    printf("child id:[%d], cpid:[%d]\n", i, pid);
    //父进程的操作线程关闭在执行中
    pid_t wpid;
    int status;
    while (1)
    {
        //这边第一参数是关闭子线程的pcb的使用不能使用父进程的pcb的pid如果使用会关闭整个进程
        wpid = waitpid(-1, &status, WNOHANG);  

        //判断wpid的返回值操作 子线程的操作
        if (wpid == 0)  // 子线程在父进程中没有销毁
        {
            sleep(1);
            continue;
        }
        else if (wpid  == -1) //子线程退出的操作
        {
            printf("子线程:【%d】\n", wpid);
            //退出当前子线程    ------------------》   使用waitpid函数第一参数进程退出的
            exit(0);
        }
        else if (wpid > 0) //子线程什么原因退出程序的
        {
            if (WIFEXITED(status)) // 子线程正常退出程序的操作
            {
                printf("child:[%d], status:[%d]\n", wpid, WEXITSTATUS(status));
            }
            if (WIFSIGNALED(status))//signal 信号的处理异常
            {
                printf("child:[%d], status:[%d]\n", wpid, WTERMSIG(status));
            }
        }

    }
}

    return 0;
}

效果图片

这里写图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值