Linux 进程控制

相关概念

  • 程序: 编译好的二进制文件, 存放在磁盘上(占用的是物理内存空间), 不占用系统资源(CPU, 内存, 打开的文件, 设备, 锁…)
  • 进程: 抽象的概念, 与操作系统原理联系紧密, 是活跃的程序, 占用系统资源, 在内存中执行.
    由原来的单道程序设计转换成多道程序设计, 是CPU分成若干的时间碎片, 各个进程抢占资源去执行, 虽然程序有优先级高低, 但是只是抢占到的几率高; 即使是多核, 也是需要时才会开启其他核.
    处理速度:寄存器->cache->内存->硬盘->网络->存储介质
    其他概念: 串行和并发, CPU和MMU
  • 进程控制块 PCB 在/usr/src/linux-headers-3.15.0-30/include/linux/sched.h文件中可以查看struct task_struct 结构体定义, 包含部分定义: 进程id, 进程状态, 进程切换时需要保存和回复的CPU寄存器, 描述虚拟的地址空间信息, 当前工作目录, 文件描述符表, 用户id和组id, 会话和进程组, 资源上限(命令:ulimit -a 查看), umask掩码…
  • 进程状态: 初始态(创建时, 非常短暂), 就绪态(有执行资格, 但是没执行权限, 需要抢占资源), 运行态(正在执行), 挂起态(没有执行资格和执行权限), 终止态
    点我查看进程状态图

进程控制

程序默认的是单进程的; 下面介绍多进程的使用
创建进程函数: pid_t fork(void);(查看 Linux下使用命令:man 2 fork)
点击查看描述图
返回值: 失败返回-1, 父进程返回子进程ID, 子进程返回0
查看当前进程 ps aux | grep “要查找的程序”; ps ajx

《Linux 进程控制》 父子进程.png

刚fork完成时(父子进程之间) 1. 0-3G地址空间相同 2. PCB相同, 但是pid除外 3.其他内容由mmu映射到物理内存上, 读时共享, 写时复制

获取pid 和 ppid 对应的函数是getpid(); getppid();

//wait 函数回收子进程
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    pid_t pid;
    pid = fork();
    
    if(pid == -1) {
        perror("fork error");
        exit(-1);
    } else if(pid > 0) {
        printf("parent process\n");
    } else if(pid == 0) {
        printf("child process\n");
    }

    printf("mul process\n");
    return 0;
}

回收进程

进程有孤儿进程, 僵尸进程

  1. 孤儿进程 : 子进程活着, 父进程死了, linxu中的init进程会领养孤儿
  2. 僵尸进程 : 子进程死了, 父进程正在忙, 没有去回收子进程
  3. 进程回收 : 代码附在下边

wait – 阻塞函数
pid_t wait(int* status);
调用一次回收一个子进程资源
返回值:

0: 回收的子进程的pid;
-1: 没有子进程可以回收了;
status — 传出参数
获取退出时候的返回值

  • 正常退出( return num; exit(num); exit(num);
    )
    WIFEXITED(status) > 0

获取返回值: WEXITSTATUS(status)

  • 被信号杀死
    WIFSIGNALED(status) > 0

获取杀死子进程的信号
WTERMSIG(status)

waitpid — pid_t waitpid(pid_t pid, int *status, int options);
(可以设置非阻塞, 提高wait的效率)
pid: -1: 所有的子进程
0: 当前进程组的子进程

0(pid): 回收指定进程的pcb
-pid: 回收不在当前进程组的子进程

opttions: 阻塞: 0
非阻塞: WNOHANG 可以设置为非阻塞
可以有针对性的回收某一个子进程资源 ;需要注意的是即使是非阻塞, 也需要循环来回收子进程

//wait函数回收子进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/wait.h>


int counter = 100;

int main(int argc, const char* argv[])
{
    int number = 5;

    int i;
    pid_t pid;

    for(i=0; i<number; ++i)
    {
        pid = fork();
        if(pid == 0)
            break;
    }

    if(i<number)
    {
        // 子进程
        counter += 100;
        printf("child pid = %d, ppid = %d\n", getpid(), getppid());
        printf("counter = %d\n\n", counter);
        //sleep(100);
        exit(9);
    }
    else if(i == number)
    {
        counter += 300;
        printf("parent pid = %d, ppid = %d\n", getpid(), getppid());
        printf("counter = %d\n\n", counter);
        sleep(1);

        // 回收子进程
        int status;
        pid_t wpid;
        while( (wpid=wait(&status)) != -1)
        {
            // 正常退出
            if(WIFEXITED(status))
            {
                printf("porcess exit by number: %d\n", WEXITSTATUS(status));
            }
            // 被信号杀死
            else if(WIFSIGNALED(status))
            {
                printf("process kill by signal: %d\n", WTERMSIG(status));
            }
            printf("child died pid = %d\n", wpid);
        }
    }
    

    return 10;
}

//验证父子进程是否文件共享
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>

int main(int argc, const char* argv[]) {
    int fd = open("temp", O_CREAT | O_RDWR, 0664);
    if(fd == -1) {
        perror("open error");
        exit(1);
    }

    pid_t pid = fork();
    if(pid == -1)  {
        perror("fork error");
        exit(1);
    }

    if(pid > 0) {
        char* p = "123123123";
        write(fd, p, strlen(p)+1);
    } else if(pid == 0) {
        // 睡1s保证父进程已经完成了文件的写操作
        sleep(1);
        char buf[1024];
        lseek(fd, 0, SEEK_SET);
        int len = read(fd, buf, sizeof(buf));
        printf("%s\n", buf);
    }
    close(fd);
    return 0;
}
//子进程执行不同任务, 父进程负责回收子进程
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

int main(int argc, const char* argv[])
{
    int i = 0;
    int number = 3;
    pid_t pid;

    for(i = 0; i<number; ++i)
    {
        pid = fork();
        if(pid == 0)
        {
            break;
        }
    }

    // 父进程
    if(i == number)
    {
        sleep(2);
        // 回收子进程
        pid_t wpid;
        int status;
        while( (wpid = waitpid(0, &status, WNOHANG)) != -1 )
        {
            if(wpid == 0)
            {
                continue;
            }
            printf("child pid = %d\n", wpid);
            if(WIFEXITED(status))
            {
                printf("return number: %d\n", WEXITSTATUS(status));
            }
            else if(WIFSIGNALED(status))
            {
                printf("exit by signal: %d\n", WTERMSIG(status));
            }
        }
    }
    else if(i == 0)
    {
        execl("/home/kevin/test/app", "app", NULL);
    }
    else if(i == 1)
    {
        execl("./error", "error", NULL);
    }
    else if(i == 2)
    {
        execlp("ps", "ps", "aux", NULL);
    }

    printf("over......\n");
    return 0;
}

//waitpid 来回收子进程, 注意非阻塞时也需要循环去回收
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

int main(int argc, const char* argv[])
{
    int num = 3;
    int i = 0;
    pid_t pid;

    for(i=0; i<num; ++i)
    {
        pid = fork();
        if(pid == 0)
        {
            break;
        }
    }

    if(i == 0)
    {
        execlp("ps", "ps", "aux", NULL);
        perror("execlp ps");
        exit(1);
    }
    else if(i == 1)
    {
        execl("/home/kevin/test/app", "app", NULL);
        perror("execl app");
        exit(1);
    }
    else if(i == 2)
    {
        execl("./error", "error", NULL);
        perror("execl error");
        exit(1);
    }
    else if(i == num)
    {
        // 回收
        int status;
        pid_t wpid;
        while( (wpid = waitpid(-1, &status, WNOHANG)) != -1 )
        {
            if(wpid == 0)
                continue;
            printf(" ----- child died pid = %d\n", wpid);
            if(WIFEXITED(status))
            {
                printf("return value %d\n", WEXITSTATUS(status));
            }
            else if(WIFSIGNALED(status))
            {
                printf("died by signal: %d\n", WTERMSIG(status));
            }
        }
    }
    return 0;
}

    原文作者:dab61956e53d
    原文地址: https://www.jianshu.com/p/a8fe21ac9a6e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞