嵌入式Linux学习笔记(4)-进程处理相关系统调用

一、什么是进程

        进程是计算机中正在运行的程序的实例。它是操作系统分配资源和调度任务的基本单位。每个进程都有自己的地址空间、内存、文件描述符、线程等资源。

        进程可以包括一个或多个线程,这些线程共享同一进程的资源,并在同一进程中执行并发任务。

        进程之间是相互独立的,彼此之间不能直接访问对方的资源,但可以通过进程间通信来进行数据交换。

        操作系统通过分配时间片给各个进程,使得它们在单个处理器或多个处理器上能够并发地运行。

        进程的创建、结束和切换是由操作系统负责管理的。

二、创建进程

1、查看进程 id

        每个进程都会对应一个唯一 id,这个 id 可以用函数 getpid() 获得,一个进程的父进程可以用 getppid() 获得。如下面代码:

printf("子进程执行:%d,父进程是:%d\n",getpid(),getppid());

        终端显示结果如下:

子进程执行:7168,父进程是:7167

2、fork

pid_t pid = fork(); 

        fork 用于创建子进程,返回值为 -1 代表创建出错,返回 0 代表成功创建的子进程 id ,返回非零正数代表父进程 id。

        fork 在创建子进程后,后面的代码在父子进程中各执行一次。比如下面代码:

    pid_t pid = fork(); //后面的代码在父子进程中各执行一次

    printf("此次pid值为:%d\n",pid);

    if (pid < 0)
    {
        printf("进程出错\n");
        return 1;
    } else if (pid == 0)
    {
        printf("子进程执行:%d,父进程是:%d\n",getpid(),getppid());
    } else
    {
        printf("父进程执行:%d,子进程是:%d\n",getpid(),pid);
    }

        终端显示结果如下:

此次pid值为:7168
父进程执行:7167,子进程是:7168
此次pid值为:0
子进程执行:7168,父进程是:7167

3、execve

        系统调用 execve 函数,系统会调用一个全新的程序代替旧的程序,不执行下面代码,删除旧程序的所有变量,只保留进程号,父进程 id,进程组 id 等。函数原型如下:

int execve (const char *__path, char *const __argv[],char *const __envp[])

        path:可执行程序的路径
        argv:传入的参数
        格式:程序的名称(执行程序的路径)+ 执行程序需要传入的参数 + NULL
        envp:传递的环境变量,如果为绝对路径则不需要环境变量,如果传的是 ping这种命令,则需要环境变量,一般为path路径(echo $PATH)
        格式:(PATH路径)+ NULL
        return:返回值是-1表示跳转失败,成功不返回且不执行下面代码

        如下面代码,目的是跳转到:/home/liuyuhui/c_code/process/ 目录下的 test 可执行文件,在运行后程序执行到这里会直接执行 test 中的代码。

    char *args[] = {"/home/liuyuhui/c_code/process/test",name,NULL};
    char *envs[] = {NULL};
    int re = execve(args[0],args,envs);
    if (re == -1)
    {
        perror("execve");
        return 1;
    }

4、waitpid

        waitpid函数是一个用于等待子进程状态改变的系统调用函数。该函数可用于父进程等待子进程结束以解决如下等问题:

        1、孤儿进程:通常子进程如果结束了需要被父进程回收,可是如果父进程先于子进程结束,子进程就会变成孤儿进程,系统会寻找父进程的父进程,直到找到没结束的进程,然后将该进程挂载上去。这样该子进程脱离了终端,用户就无法通过输入设备进行操控;

        2、僵尸进程:在每个进程退出的时候,内核会释放所有的资源,包括打开的文件,占用的内存等。但是仍保留一部分信息(进程号PID,退出状态,运行时间等)。直到父进程通过 wait 或 waitpid 来取时才释放。如果父进程没有调用 wait 或者 waitpid 就会产生僵尸进程。僵尸进程会导致进程号一直被占用,但是系统所能使用的进程号是有限的,如果大量产生僵尸进程,将因没有可用的进程号而导致系统无法产生新的进程。

        该函数原型如下:

pid_t waitpid(pid_t pid, int *status, int options);
  • pid:指定等待的子进程ID。有以下几种取值:
    • pid > 0:等待进程ID为pid的子进程。
    • pid = -1:等待任意子进程。相当于 wait 函数。
    • pid = 0:等待与调用进程属于同一进程组的任意子进程。
    • pid < -1:等待进程组ID为pid绝对值的任意子进程。
  • status:用于存储子进程的终止状态信息。如果不关心子进程的终止状态,可以将status设为NULL。如果status不为NULL,则可以使用一些宏来解析终止状态:
    • WIFEXITED(status):如果子进程正常终止,则返回true。
    • WEXITSTATUS(status):如果WIFEXITED为true,则返回子进程的退出状态。
    • WIFSIGNALED(status):如果子进程因为信号而终止,则返回true。
    • WTERMSIG(status):如果WIFSIGNALED为true,则返回导致子进程终止的信号编号。
  • options:用于指定额外的选项。常用的选项有:
    • WNOHANG:非阻塞模式,即如果没有子进程终止或状态没有改变,则立即返回0。
    • WUNTRACED:除了等待终止的子进程,还等待暂停(stop)的子进程。

        waitpid函数会阻塞调用进程,直到满足以下条件之一:

  •         某个子进程终止。
    • 某个子进程暂停(stop)并且没有被父进程忽略。

        当waitpid返回时,返回值为子进程的PID,或者出错时的-1。

三、综合案例

        如下代码,创建了两个进程,子进程使用 ping 命令进行五次网络诊断,父进程等待子进程运行完毕后再结束。

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

int main(int argc, char const *argv[])
{
    int subprocess;

    printf("liuyuhui is study in the classroom\n");

    pid_t pid = fork();

    if (pid == -1)
    {
        perror("pid");
        printf("\n");
        return 1;
    }else if (pid == 0)
    {
        //son_process
        char *args[] = {"/usr/bin/ping","-c","5","www.atguigu.com",NULL};
        char *envs[] = {NULL};

        printf("liuyuhui open the internet ten times\n");

        int exR = execve(args[0],args,envs);

        if (exR == -1)
        {
            perror("execve");
            printf("\n");
            return 1;
        }
    }else{
        //father_process
        printf("father: %d wait son: %d\n",getpid(),pid);

        waitpid(pid,&subprocess,0);
    }
    
    printf("liuyuhui login succeed\n");


    return 0;
}

        如下为终端运行结果:

liuyuhui is study in the classroom
father: 8581 wait son: 8582
liuyuhui open the internet ten times
PING www.atguigu.com.w.kunluncan.com (113.200.122.200) 56(84) bytes of data.
64 bytes from 113.200.122.200: icmp_seq=1 ttl=56 time=100 ms
64 bytes from 113.200.122.200: icmp_seq=2 ttl=56 time=225 ms
64 bytes from 113.200.122.200: icmp_seq=3 ttl=56 time=147 ms
64 bytes from 113.200.122.200: icmp_seq=4 ttl=56 time=168 ms
64 bytes from 113.200.122.200: icmp_seq=5 ttl=56 time=89.4 ms

--- www.atguigu.com.w.kunluncan.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 89.378/145.816/224.748/49.025 ms
liuyuhui login succeed
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值