3.进程

一.fork()

fork()用来创建一个子进程,子进程复制父进程的0-3G空间和父进程内核中的PCB,但子进程和父进程的id号不同。

fork()调用一次,返回两次

在父进程中返回子进程的PID,在子进程中返回0。

例:

复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    pid_t pid;
        
    pid = fork();
    if (pid > 0) {
        printf("cur process is parent\n");
        printf("cur pid is: %d\n", getpid());
        printf("cur parent pid is: %d\n", getppid());
        while(1);
    } else if (pid == 0) {
        printf("cur process is child\n");
        printf("cur pid is: %d\n", getpid());
        printf("cur parent pid is: %d\n", getppid());
        while(1);
    } else {
        perror("fork");
    }
    
    return 0;
}
复制代码

运行结果:

cur process is parent
cur pid is: 5924
cur parent pid is: 2736
cur process is child
cur pid is: 5925
cur parent pid is: 5924

二.execl()&execv()&execle()&execve()&execlp()&execvp()

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execv("/bin/ps", ps_argv);
execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
execve("/bin/ps", ps_argv, ps_envp);
execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
execvp("ps", ps_argv);

PS:

1.只有execve是真正的系统调用,其它五个函数最终都调用execve

2.由于exec函数只有错误返回值,只要返回了一定是出错了,所以不需要判断它的

返回值,直接在后面调用perror即可

例:

复制代码
#include <unistd.h>
#include <stdlib.h>

int main()
{
    
    // execl("/bin/ls", "ls", "-l", NULL);
    char *const ps_argv[] = {"ps", "aux", NULL};
    //execvp("ps", ps_argv);
    execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
    perror("exec ps");
    exit(1);
    return 0;
}
复制代码

运行结果:

PID PPID PGRP SESS TPGID COMMAND
2699 2693 2699 2699 3926 bash
3926 2699 3926 2699 3926 ps

三.wait()&waitpid()

◆ wait()

僵尸进程: 子进程退出,父进程没有回收子进程资源(PCB),则子进程变成僵尸进程(Z+)(当子进程运行结束后,其用户空间已被释放,但它的PCB没有被立即释放,等待父进程将其释放)
孤儿进程: 父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为1号进程init进程,称为init进程领养孤儿进程

可使用wait()函数除去僵尸进程

PS:

1.wait()函数是一个阻塞函数,等待回收子进程资源,如果没有子进程,wait返回-1
2.waitpid()函数则是一个非阻塞函数

复制代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>


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

    if (pid > 0) {
        while (1) {
            printf("I am parent process\n");
            printf("wait for child: %d\n", wait(NULL));
            sleep(1);
        }
    } else if (pid ==0) {
        printf("I am child process\n");
        printf("My pid is: %d\n", getpid());
        sleep(10);
    } else {
        perror("fork");
    }
    
    return 0;
}
复制代码

运行结果:

I am parent process
I am child process
My pid is: 5308
wait for child: 5308
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1
I am parent process
wait for child: -1

◆ waitpid()

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


< -1 回收指定进程组内的任意子进程
-1 回收任意子进程
0 回收和当前调用waitpid一个组的所有子进程
> 0 回收指定ID的子进程

WNOHANG 如果没有子进程退出立即返回,这样就实现了非阻塞的wait

复制代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>


int main()
{
    pid_t pid;
    pid = fork();
    
    if (pid > 0) {
        while (1) {
            printf("I am parent process\n");
            pid_t pid_c = waitpid(0, NULL, WNOHANG);
            printf("go to next...\n");
        }    
    
    } else if (pid == 0) {
        printf("I am child process\n");
        sleep(10);
    } else {
        perror("fork");
    }
    return 0;
}
复制代码

运行结果:

I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...
I am parent process
go to next...

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   夜行过客  阅读(252)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
历史上的今天:
2016-11-24 新浪微博客户端(37)-发布新微博
2016-11-24 新浪微博客户端(36)-自定义带placeholder的TextView
2016-11-24 iOS-开启arc之后 NSNotificationCenter removeObserver 是否需要调用
2016-11-24 新浪微博客户端(35)-使用NSMutableAttributedString实现多行文本的效果
2016-11-24 android-android获取navigationview 上的控件id
点击右上角即可分享
微信分享提示