进程及其相关接口函数

本文介绍了Linux中的进程概念,包括程序与进程的区别、进程的类型和状态,详细阐述了进程的创建(fork)、结束(exit/_exit)、回收(wait、waitpid)以及如何创建守护进程。此外,还提供了创建守护进程并记录时间的日志实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、进程

程序:静态的,有序指令的集合

进程:是系统分配资源的总称,是程序执行的一次完整过程(创建、调度、执行、消亡)

(1)程序的组成:

​ 正文段、用户数据段、系统数据段(PCB<进程控制块>、PC、堆栈)

<1>PCB:

  • ​ 进程ID
  • ​ 用户名、用户组名
  • ​ 进程的状态、优先级
  • ​ 文件描述符表

<2>PC(程序寄存器):

  • ​ 记录程序下一条指令的地址
  • ​ 堆栈(栈)
(2)进程的类型

​ <1>交互进程:和终端相关,可以在前台运行,也可以在后台

​ <2>批处理进程:和终端无关,可以将指定的进程放在一个工作队列中按顺序执行,一般由系统管理员操作

​ <3>守护进程:和终端无关,在后台一直循环执行任务

(3)进程的状态
进程相关指令
ps -ef -->查看当前系统进程
ps -aux -->查看当前系统进程,还会1显示当前进程状态
top -->每隔三秒,显示进程的实时信号

​ <1>运行态(就绪态)–R–正在运行或准备运行的进程

​ 等待态: [区别在于能否被信号打断]

​ <3>可中断等待态–S–

​ <4>不可中断等待态–D–

​ <5>暂停态–T–暂停运行,直到有信号唤醒位置

​ <6>僵尸态–Z–进程结束后,没有进行资源回收,该进程变为僵尸态

2、进程相关接口函数

1、创建子进程–fork
#include <sys/types.h>
#include <unistd.h>

pid_t fork(void);
返回值:
    成功创建一个新的子进程,父进程返回子进程的PID号,子进程返回0
    失败父进程返回-1,没有子进程被创建
    PPId-->父进程
    
getpid()--->获取当前进程的pid    
    

父子进程:

一 个进程通过 fork 函数创建一个新的进程,原本进程称为新进程的父进程,新的进程称为原进程的子进程

子进程会维承父进程中几乎所有数据

(1)、如果父进程优先于子进程结束:

​ 子进程称为孤儿进程,由前台进程变为后台进程,统一由init进程收养

(2)、如果子进程优先于父进程结束:

​ 子进程状态变为僵尸态

一般来说,如果子进程先于父进程结束,子进程应该统一由父进程回收

​ ***子进程在 fork语句的下一条指令开始执行

虽然当父进程结束后系统会自动回收,不过当是一些不方便结束的父进程:
如:服务器、网页等,我们就需要把进程给结束掉,所有接下来时进程的结束。

2、结束进程–exit()/_exit()
#include <stdlib.h>

       void exit(int status);
	参数:
        status:表示进程退出的状态
--------------------------------------------------------
#include <unistd.h>

       void _exit(int status);
    
注:exit函数调用后会刷新所有缓冲区,_exit函数不会刷新
    

在多个进程中,当一些进程结束时,进程可能出现僵尸态,越积越多最终会导致系统或者服务器崩溃,所有僵尸态是我们必须要避免发生的,下面会给到进程回收的两种方式,看个人习惯,合理使用。

3、进程回收–wait、waitpid
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);
参数:
    wstatus:进程结束时,状态信息的首地址
返回值:
    成功返回子进程结束的pid号,失败返回-1---------------------------------------------------------    
pid_t   waitpid(pid_t   pid,   int *wstatus, int options);
	参数:
        pid:进程号,-1(任意的意思,谁先结束先接受谁)
        wstatus:进程结束时,状态信息的首地址
        options:
        	0--以阻塞的方式等待子进程结束
        	WNOHANG--以非阻塞方式等待子进程结束·

4、守护进程

守护进程和终端无关,负责在后台周期性地处理某些事件或等待某些事件响应

(1)进程组

​ 当用户执行一个进程时,就相当于创建了一个进程组,跟该进程具有亲缘关系的所有进程都属于该进程组

(2)会话

​ 当用户打开一个终端时,就创建了一个会话,一个会话由一个或多个进程组组成,一旦终端关闭,该会话中所有进程组中的进程全部结束

(3)守护进程的创建流程:
1、创建子进程,父进程退出
    fork();
2、让子进程脱离原本会话
    setsid();
3、修改当前工作路径(非必要,但'一般都会改')
    chdir("/tmp");
4、重设文件权限掩码(非必要)
    umask(0);
5、删除进程中的所有文件描述符
    getdtablesize();
eg:
	int i=0;
	for(i=o;i<getdtablesize;i++)
    {
        close(i);
    }
	while(1)
    {
        周期性的需要执行的事件;
    }
5、实例:

创建一个守护进程,在time.log日志文件中,每隔一秒,记录当前时间

分析:因为要持续不断地去记录时间并存在time文件日志中,所以我们可以开两个进程,父进程和子进程,并将子进程挂到后台,而回收父进程的资源空间,使其形成一个保护进程,就可以不断地去记录时间。

代码演示:

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

int main(int argc, char *argv[])
{ 
    //struct stat buf;
    struct tm *t_log;//定义一个结构体指针
    FILE *fp = fopen("time.log","a+");
    char arr[100]={0};//定义缓冲区大小
    int ret=-1;
    int status,end,line=1;
    pid_t pid=fork();
    time_t t;//定义一个time_t类型的变量,用于时间的输出
    
    if(NULL==fp)
    {
        perror("open");
        exit(-1);
    }
    memset(arr,0,sizeof(arr));//先给缓冲区清0
    while((end=getc(fp))!=EOF)//一行读完是结束
    {
        if(end=='\n') line++;
    }
    if(pid==0)//子进程
    {
        setsid();
        while(1)
        {
            time(&t);
            t_log=localtime(&t);//获取时间
            sprintf(arr," %d年%d月%d日%d:%d:%d\n",t_log->tm_year+1900,t_log->tm_mon+1,t_log->tm_mday,t_log->tm_hour,t_log->tm_min,t_log->tm_sec);//打印时间,可打印自己想要的的格式
            fwrite(arr,sizeof(char),strlen(arr),fp);//写入time.log日至文件
            fflush(fp);//刷新
            sleep(1);//延迟一秒
        }  
    }
    else
    {
        ret =waitpid(pid,&status,0);//回收进程
        if(ret<0)
        {
            perror("wait");
            exit(-1);
        }
        else//父进程
        {
            printf("pid=%d\n",pid);
        }
    }
    return 0;
} 

FILE *fopen(const char *pathname,const char *mode);
参数:
pathname:打开文件的文件名(包含路径)
mode:打开文件的方式
r:以只读的方式打开文件,文件必须要存在
r+:以读写方式打开,文件必须要存在
w:以只写方式打开文件,如果文件不存在,则会创建再打开
w+:以读写方式打开文件,如果文件不存在,则会创建再打开
a:以只写方式打开文件,如果文件不存在,则会创建再打开
a+:以读写方式打开文件,如果文件不存在,则会创建再打开

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值