进程控制编程

1.基本概念

1.1什么是进程

进程是正在执行的程序,程序只是静态概念。进程包含了创建,调度,消亡,是程序执行和资源管理的最小单位

pstree查看进程之间的关系
ps  -ef 查看进程pid
ps -aux查看进程信息
ps -axjf

1.2什么是进程组

对相同的进程进行管理,进程组id为pgid,由首进程id决定,通过命令ps -axjf查看。通过管道连接的两个程序就属于同一个进程组

1.3什么是会话

会话管理一堆的进程组,进入ubuntu桌面系统就是开启了一个会话,也就是说会话一般关联着一个终端

1.4守护进程

守护进程独立于控制台,周期性运行,不需要用户输入,其父进程是init进程。当关闭终端时,会话中所有的进程都会被关闭,而守护进程则还会继续运行。守护进程通常以d结尾,比如sshd,xinetd,crond这些。通过daemon函数创建。

1.5进程状态

执行态:该进程正在执行,即进程正在占用 CPU
就绪态:进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片
阻塞态: 进程还不具备占用 CPU 的权力,若等待时间发生可将其唤醒
在这里插入图片描述

2.进程基本操作

2.1 进程标识

进程也是通过一系列数字表示进程号,称之为PID,父进程号PPID,也都是非零整数。通过getpid和getppid获取

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

int main(int argc, char **argv)
{
    pid_t x = getpid();  //获取当前进程PID
    pid_t y = getppid(); //获取父进程PID

    printf("%d\r\n", x);
    printf("%d\r\n", y);
}

2.1 进程创建与退出

在进程中使用 fork 函数,则会创建一个新进程,新的进程称为子进程,原来的进程则称为父进程。fork 函数的特别之处在于函数执行一次却返回两个值。 重点是,父进程返回的是子进程的进程号,而子进程返回 0。因此,可以通过返回值来判定该进程是父进程还是子进程。

可怕的是,使用 fork 函数得到的子进程几乎就是父进程的复制品,它继承了它爹很多很多东西,比如进程上行文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等等,而子进程独有的只有它的进程号、资源使用和计时器等。因此可以看出,使用 fork 函数的执行速度并不很快。如果想知道 fork 函数是如何复制的,可以参考《Linux 内核设计与实现》这本书,结合 Linux 源码来分析。

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

int main(int argc, char **argv)
{
    pid_t result;
    result = fork(); //相当于fork之后执行了2次,不过是在两个进程里面。system函数可用启动一个进程

    if (-1 == result)
    {
        printf("create process fail\r\n");
        exit(1);
    }
    else if (0 == result)
    {
        printf("current value is %d in child process,child pid is %d\r\n", result, getpid());
    }
    else
    {
        printf("current value is %d in father process,father pid is %d\r\n", result, getppid());
    }
    return 0;
}

结果:输出顺序可能不一样,两个进程先后执行顺序是不确定的

xx@ubuntu:~/Desktop$ ./a.out 
current value is 5126 in father process,father pid is 4971
xx@ubuntu:~/Desktop$ current value is 0 in child process,child pid is 5126

还有一个函数叫 vfork,它也可以创建新进程,但是它不产生父进程的副本。它是通过允许父子进程可以访问相同物理内存从而伪装了对进程地址空间的真实拷贝,当子进程需要改变内存中数据时才真实拷贝父进程。这就是著名的“写操作时拷贝”技术(copy-on-write)

2.2 给子进程收尸

wait或者waitpid 函数获取子进程退出状态,如果没有这样步,则子进程的相关信息一直占用内存。WIFEXITEX(status),WIFSIGNALED(status)可用这两个宏判断是正常退出还是异常退出

2.2.1僵尸进程

子进程先退出,父进程没有调用wait函数,子进程就变成了僵尸进程

2.2.2孤儿进程

父进程先退出,子进程就变成了孤儿进程,最后init进程收集收集退出状态

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

int main(int argc, char **argv)
{
    pid_t c_pid, get_pid;
    c_pid = fork();

    if (c_pid < 0)
    {
        printf("fork\r\n");
    }
    else if (c_pid == 0)
    {
        printf("sleep 3s in child\r\n");
        sleep(3);
        exit(0); //先处理缓冲区的数据再退出,_exit()不处理缓冲区的数据,直接退出了。如果printf不加回车换行,则不会打印的,exit()会打印
    }
    else
    {
        do
        {
            //子进程没有退出,则返回0
            get_pid = waitpid(c_pid, NULL, WNOHANG); //最后一个参数WNOHANG意味着父进程不会被阻塞
            if (get_pid == 0)
            {
                printf("child process has not exit\r\n");
            }
        } while (!get_pid);

        if (get_pid == c_pid)
        {
            printf("child process has exit\r\n");
        }
    }
    return 0;
}
#截取一部分
child process has not exit
child process has not exit
child process has not exit
child process has not exit
child process has not exit
child process has not exit
child process has not exit
child process has exit

3.exec函数族

exec 函数族可以根据文件名或目录找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新进程替换了。这里的可执行文件既可以是二进制文件,也可以是 Linux 下任何可执行的脚本文件。这些都是可变参数,调用的时候,最后一个参数NULL表示没有参数了

在这里插入图片描述

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

int main(int argc, char **argv)
{
    if (fork() == 0)
    {
        //当执行execlp这个函数了,就不会再执行if里面的内容了,否则就表示失败
        if (execlp("ps", "ps", "-ef", NULL) < 0) //如果为execl,则第一个参数必须/开头,表示目录,否则会认为是文件,最后参数必须为NULL
        {
            perror("execlp :");
            exit(1);
        }
    }
    return 0;
}

结果:在环境变量PATH中查找可执行文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值