首页 > 系统相关 >Linux进程API接口功能介绍和使用方法

Linux进程API接口功能介绍和使用方法

时间:2024-04-07 09:33:48浏览次数:25  
标签:status fork 函数 pid 接口 API exit Linux 进程

目录

概述

1 进程基本操作

1.1 fork函数

1.2 终止进程

1.3 exec 族函数

1.4 wait函数

1.5 守护进程

2 使用进程相关API的范例

2.1 创建进程

2.1.1 功能介绍

2.1.2 编写代码

2.1.3 运行结果

2.2 等待退出函数

2.2.1 功能介绍

2.2.2 编写代码

2.2.3 运行结果

2.3 使用守护进程

2.3.1 功能介绍

2.3.2 编写代码

2.3.3 运行结果

3 参考文献


概述

本文介绍linux进程相关的函数接口,详细介绍每个函数的功能和使用方法。然后使用这些接口,编写3个范例,便于理解其在实际编程的应用方法。

1 进程基本操作

1.1 fork函数

一个现有的进程可以调用 fork()函数创建一个新的进程,

父进程: 调用 fork()函数的进程称为父进程

子进程: 由 fork()函数创建出来的进程被称为子进程(child process)

fork()函数原型如下所示(fork()为系统调用) :

#include <unistd.h>
​
pid_t fork(void);

fork()函数从运行着的进程中分裂出一个子进程,它通过拷贝父进程的方式创建子进程。 子进程与父进程有相同的代码空间、文件描述符等资源。

进程创建后,子进程与父进程开始并发执行, 执行顺序由内核调度算法来决定。fork()函数如果成功创建了进程, 就会对父子进程各返回一次,其中对父进程返回子进程的 PID,对子进程返回 0;失败则返回小于 0 的错误码。

1.2 终止进程

进程终止可分为正常终止和异常终止两大类, 其中常见的正常终止方式有:

正常终止方式实现方法
方式-1从 main()函数 return 返回
方式-2实现方法调用类 exit()函数
异常终止方式实现方法
方式-1调用 abort()函数
方式-2接收到一个信号终止

main()函数使用 return 指令返回时会自行调用类 exit()函数来终止进程。异常终止的abort()函数是通过 SIGABRT 信号来实现的。

#include <stdlib.h>
​
void exit(int status);

参数 status 为进程的退出状态,与 main()函数中 return 的返回值有相同效果,即在程序中:

exit(0);

1.3 exec 族函数

exec 族函数用来修改当前进程的代码空间。 fork()函数的时候提到,在创建进程后子进程与父进程有相同的代码空间;而在实际应用中, 往往需要子进程去执行另外一个程序, 像这种情况,可以在子进程中调用 exec 族函数它的代码段完全替换为新的程序,并从这个新进程的 main 函数开始执行。例如在子进程中执行“/bin/ls”程序:

调用 exec 族函数并不创建进程,因此前后进程的 ID 并无改变, exec 只是用一个全新的程序替换掉当前进程代码空间里的内容。 exec 族函数有 6 个不同的 exec 函数,函数原型分别如下:

#include <unistd.h>
​
extern char **environ;
​
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,..., 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[]);

以上函数是在 exec 后面加上如 l、 p、 e、 v 等元素组合成的后缀形成的,这些函数只在参数列表上存在差别

后缀 p:

表示使用 filename 做参数,如果 filename 中包含“/” 则视其为路径名,否则将会在 PATH 环境变量所指定的各个目录中搜索该文件,如 execlp()函数。无后缀 p 则必须使用路径名来指定可执行文件的位置,如 execl()函数。

后缀 e:

表示可以传递一个指向环境字符串指针数组的指针,环境数组需要以 NULL 结束,如 execvpe()函数。而无此后缀的函数则将当前进程的 environ 变量复制给新的程序,如execv()函数。

后缀 l:

表示使用 list 形式来传递新程序的参数,所有这些参数均以可变参数的形式在exec 中给出,最后一个参数需要是 NULL 用以表示没有更多的参数了,如 execl()函数。

后缀 v:

表示使用 vector 形式来传递新程序的参数,传给新程序的所有参数放入一个字符串数组中,数组以 NULL 结束以表示结尾,如 execv()函数。

exec 族函数只有在出错的时候才会返回,如果成功无返回,否则返回-1。

1.4 wait函数

wait()函数用来帮助父进程获取其子进程的退出状态。当进程退出时,内核为每一个进程保存了一定量的退出状态信息,父进程可根据此退出信息来判断子进程的运行状况。如果父进程未调用 wait()函数,则子进程的退出信息将一直保存在内存中。

由于进程终止的异步性,可能会出现子进程先终止或者父进程先终止的情况,从而出现两种特殊的进程:

进程类型描述
僵尸进程如果子进程先终止,但其父进程没有为它调用 wait()函数, 那么该子进程就会变为僵尸进程。僵尸进程在它的父进程为它调用 wait() 函数之前将一直占有系统的内存资源。
孤儿进程如果父进程先终止,尚未终止的子进程将会变成孤儿进程。孤儿进程将 直接被 init 进程收管,由 init 进程负责收集它们的退出状态

调用 wait()函数的进程将挂起等待直到它的任一个子进程终止, wait()函数原型如下:

#include <sys/types.h>
#include <sys/wait.h>
​
pid_t wait(int *status);

参数 status 是一个用来保存子进程退出状态的指针, 若函数执行成功,将返回获取到退出状态进程的 PID,否则返回-1。

描述
WIFEXITEX(status)若为正常终止子进程返回状态,则为真。对于这种情况可以执行 WEXITSTATUS(status),取自子进程传给 exit, return 参数的低 8 位。
WIFSIGNALED(status)若为异常终止子进程返回状态,则为真(接收到一个不捕捉的信号)。对于这种情 况可以执行 WTERMSIG(status)获取使子进程退出的信号

1.5 守护进程

守护进程(Daemon) 是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件,它不需要用户输入就能运行并提供某种服务。守护进程的父进程是 init 进程,因为它真正的父进程在 fork 出该子进程后就先于该子进程 exit 退出了,所以它是一个由 init 领养的孤儿进程。守护进程是非交互式程序,没有控制终端,所以任何输出(无论是向标准输出设备还是标准错误输出设备的输出) 都需要特殊处理。 Linux 系统的大多数服务器就是通过守护进程实现的,且通常以字母 d 结尾来命名进程 名, 比如 sshd、 xinetd、 crond 等。Linux 系统有多种创建守护进程的方法,其中最常用的是使用 daemon()函数来创建守护进程。

daemon()函数的原型如下 :

#include <unistd.h>
​
int daemon(int nochdir, int noclose);

参数介绍:

参数描述
nochdir如果传入 0,则 daemon 函数将调用进程的工作目录设置为根目录, 否则保持原有的工作目录不变
noclose如果传入 0,则 daemon 函数会将标准输入、标准输出、标准错误重 定向到/dev/null 文件中,否则不改变这些文件描述符。

该函数如果成功则返回 0,否则返回-1,并设置 errno。

2 使用进程相关API的范例

2.1 创建进程

2.1.1 功能介绍

使用fork()创建进程,并打印进程的ID

2.1.2 编写代码

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     :  test_process.c
作者       : [email protected]
版本       : V1.0
描述       : process API test
其他       : 无
日志       : 初版V1.0 2024/03/04
​
***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) 
{
    pid_t pid;
    
    pid = fork();           /* 创建进程 */
    if (pid == 0) {         /* 对子进程返回 0 */
        printf("Here is child, my pid = %d, parent's pid = %d\n", 
                getpid(), getppid()); /* 打印父子进程 PID */
        exit(0);
    } 
    else if(pid > 0) {        /*对父进程返回子进程 PID */
        printf("Here is parent, my pid = %d, child's pid = %d\n", getpid(), pid);
    } 
    else {
        perror("fork error\n");
    }
    return 0;
}

2.1.3 运行结果

2.2 等待退出函数

2.2.1 功能介绍

使用正常和异常两种方式,退出进程。

2.2.2 编写代码

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     :  test_thread.c
作者       : [email protected]
版本       : V1.0
描述       : process API test
其他       : 无
日志       : 初版V1.0 2024/03/04
​
***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
​
static void print_exit_status(int status) 
{   
     /* 自定义打印子进程退出状态函数 */
    if (WIFEXITED(status))             /* 正常退出,打印退出返回值 */
    {
        printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
    }
    else if (WIFSIGNALED(status)){      /* 因信号异常退出,打印引起退出的信号 */
        printf("abnormal termination, signal number = %d\n", WTERMSIG(status));
    }
    else{
        printf("other status\n");      /* 其它错误 */
    }
}
​
int main(int argc, char *argv[]) 
{
    pid_t pid;
    int status;
    
    if ((pid = fork()) < 0) {    /* 创建子进程 */
        perror("fork error");
        exit(-1);
    } 
    else if (pid == 0) {
        exit(7);                  /* 子进程调用 exit 函数,参数为 7 */
    }
    
    if (wait(&status) != pid) {   /* 父进程等待子进程退出,并获取退出状态*/
        perror("fork error");
        exit(-1);
    }
    
    print_exit_status(status);     /* 打印退出状态信息 */
    if ((pid = fork()) < 0) {      /* 创建第二个子进程 */
        perror("fork error");
        exit(-1);
    } 
    else if (pid == 0) {
        abort();                    /* 子进程调用 abort()函数异常退出 */
    }
    
    if (wait(&status) != pid) {     /* 父进程等待子进程退出,并获取退出状态*/
        perror("fork error");
        exit(-1);
    }
    
    print_exit_status(status);      /* 打印第二个退出状态信息 */
    
    return 0;
}
​

2.2.3 运行结果

运行程序后,通过log可得,一个进程正常退出,另外一个进程是异常退出。

2.3 使用守护进程

2.3.1 功能介绍

使用 daemon()函数创建守护进程的用法,变为守护进程后程序每60 秒打印当前的时间信息到/tmp/daemon.log 文件中。

2.3.2 编写代码

/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     :  test_thread.c
作者       : [email protected]
版本       : V1.0
描述       : process API test
其他       : 无
日志       : 初版V1.0 2024/03/04
​
***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
​
​
int main(void)
{
    int fd;
    time_t curtime;
    
    if(daemon(0,0) == -1) {
        perror("daemon error");
        exit(-1);
    }
    
    fd = open("/tmp/daemon.log", O_WRONLY | O_CREAT|O_APPEND, 0644);
    if (fd < 0 ) {
        perror("open error");
        exit(-1);
    }
    
    while(1) {
        curtime = time(0);
        char *timestr = asctime(localtime(&curtime));
        write(fd, timestr, strlen(timestr));
        sleep(60);
    }
    
    close(fd);
    
    return 0;
}
​

2.3.3 运行结果

守护进程执行后将脱离控制台,可用 ps -ef 来查看。 下图的执行结果截图,执行程序将直接返回,并可以/tmp/daemon.log 文件查看到日期时间。

查询log文件内容,使用命令:

cat /tmp/daemon.log

3 参考文献

  1. 《现代操作系统》

  2. 《linux/unix系统编程手册》

标签:status,fork,函数,pid,接口,API,exit,Linux,进程
From: https://blog.csdn.net/mftang/article/details/136512192

相关文章

  • ISBN信息查询api接口
     基本说明:接口地址:http://data.isbn.work/openApi/getInfoByIsbn?isbn={isbn}&appKey={appkey}返回格式:json请求方式:get请求示例:http://data.isbn.work/openApi/getInfoByIsbn?isbn=9787513159074&appKey=ae1718d4587744b0b79f940fbef69e77伽薇 809137232请求参数说明:名......
  • 肖sir__接口测试之fiddler(10.2)
    fiddler======================================一、fiddler包安装 路径也尽量不要有中文  安装步骤:(1)点击安装包  (2)默认安装路径  (2)在点击安装install  (3)点击diddler.exe图标  (4)  ===================================== 二、Fiddler 简......
  • dd if=devzero of=的含义是什么?Linux 下的dd命令使用详解
    ddif=/dev/zeroof=的含义是什么?Linux下的dd命令使用详解一、dd命令的解释dd:用指定大小的块拷贝一个文件,并在拷贝的同时进行指定的转换。注意:指定数字的地方若以下列字符结尾,则乘以相应的数字:b=512;c=1;k=1024;w=2参数注释:1.if=文件名:输入文件名,缺省为标准输入。即指定源文......
  • Linux--进程的概念(一)
    目录一、冯诺依曼体系结构二、操作系统2.1什么是操作系统2.2操作系统的意义三、进程3.1进程的基本概念3.2描述进程——PCB3.3进程和程序的区别3.4task_struct-PCB的一种3.5task_struct的内容分类四、如何查看进程4.1通过系统文件查看进程4.2通过ps指令查看进......
  • Linux进程概念(二):进程的基本概念与进程的创建
    目录进程的基本概念进程控制块-PCB学前补充预备知识创建(子)进程创建(子)进程的原因理解fork有两个返回值进程的基本概念基本概念:程序的一个执行实例,正在执行的程序等内核层面:担当分配系统资源(CPU时间、内存)的实体操作系统如何管理进程:先描述:操作系统将一个磁盘中......
  • Linux进程状态
    大家好,我是knight-n。本篇文章我会为大家介绍进程状态。什么是进程状态进程状态是指进程在其执行过程中的不同状态。这些状态随着进程的执行和外界条件的变化而转换。在三态模型中进程状态分为三种基本状态,即运行态,就绪态,阻塞态。在五态模型中,进程分为新建态、终止态,运行态......
  • Linux挂载NTFS格式硬盘后为只读的解决办法
    在Linux中正确处理从Windows系统拿来的硬盘从Windows系统拿下来的硬盘,放在Linux系统中以后,有时候它为只读,无法进行写入的操作。虽然这两个文件系统是不同的,但在一些Linux系统中,比如Ubuntu,已经最大限度地兼容了NTFS格式硬盘。硬盘换了系统之后变成只读的主要原因是,硬盘中隐藏的分......
  • linux扩展正则表达式()
    1.()含义linux扩展正则表达式()含义是找出“用户组”字符串;此外,()还可以用来作为“多个重复用户组”的识别2.样例命令1:grep-nE'p(wp|lp|np|dp)o'anaconda-ks.cfgORegrep-n 'p(wp|lp|np|dp)o'anaconda-ks.cfg#搜索包含(pwpo)、(plpo)、(pnpo)、(pdpo)字符串的行,因......
  • Linux UVC调试工具
    v4l2-utils:v4l2-utils是一个Linux下用于视频设备管理和调试的工具集,其中包含了一些命令行工具,可以用来查询、设置和调试视频设备。 ubuntu安装v4l2-utils:sudoapt-getinstallv4l-utils 下面是v4l2-utils的一些使用方法:#列出设备v4l2-ctl--list-devices......
  • Linux命令-xargs
    声明:本文框架和思路均参考阮一峰博客的xargs命令教程xargs通常用于将A命令的输出作为B命令的输入(参数),因为一些命令的参数无法使用标准输入(stdin)而只能使用命令行对于那些可以使用stdin作为参数的命令,我们并不需要xargs,直接使用|即可如cat/etc/shells|grepbash而对于不支......