目录
一、什么是进程
进程:即正在运行的程序。
二、进程的分类
前台进程:可以直接从当代终端使用ctrl+c退出的进程
后台进程:只能使用kill杀死或者其父进程结束后才会结束的进程
按如下代码举例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#define N 100
int main(int argc, char *argv[])
{
while(1){
printf("A\n");
sleep(2);
}
return 0;
}
我们常规编译运行想要停止只需要ctrl+c即可退出,此时,我们这个正在运行的程序称为前台进程
我们此时运行./a.out &(该命令可将前台进程转换为后台进程),这时候我们会发现继续使用ctrl+c无法将该程序杀死,这样的进程我们称其为后台进程。
三、如何关闭进程
从第二点可以看出,对于前台进程,我们可以通过ctrl+c来进行关闭,那么,后台进程我们该如何杀死呢?
1、查看进程的PID(进程号)
指令:ps -ef
显示结果如下:
找到我们要杀死的进程./a.outd的进程号为4727(每个人的都不一样)
接着我们输入以下命令:
kill -9 PID号
此处我的PID号为4727,所以我的输入为:
kill -9 4727
然后再刚才的终端就会显示如下结果:
此时说明我们的进程已经被杀死。同样,前台进程我们也可以使用这种方法来杀死。
四、进程相关接口函数
1、fork()
#include <sys/types.h>
#include <unistd.h>pid_t fork(void);
返回值:
成功创建一个新的子进程,父进程返回子进程的PID号,子进程返回0
失败父进程返回-1,没有子进程被创建
2、exit()
#include <stdlib.h>
void exit(int status);参数:
status:表示进程退出的状态
3、wait()
#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *wstatus);
参数:
wstatus:进程结束时,状态信息的首地址返回值:
成功返回结束子进程的pid号,失败返回-1
4、exec()
#include <unistd.h>
int execl(const char *pathname, const char *arg, .../* (char *) NULL */);
参数:
pathname:要执行程序的文件名
arg:表示执行程序的命令行参数,命令行参数列表最终以NULL结尾
返回值:
失败返回-1;
五、守护进程的创建
1、进程组的概念
当用户执行了一个程序时,就相当于创建了一个进程组,跟该进程具有亲缘关系的所有进程都属于该进程组。
2、会话
当用户打开一个终端时,就创建了一个会话,一个会话由一个或者多个进程组组成,一旦终端关闭,该会话中所有进程组中的进程全部结束。
3、创建
(1)创建子进程,父进程退出,得到孤儿进程
fork()函数打开,exit()退出父进程
(2)让子进程脱离原本会话
setsid()
(3)修改当前工作路径(非必要,一般都会改)
chdir():修改当前工作路径
int chdir(const char *path);path一般为“ / ”或者“ /tmp ”
(4)重设文件权限掩码(非必要,一般都会改)
umask(0);
(5)删除进程中所有的文件描述符(必须要操作)
getdtablesize()//获取最大的文件描述符
int i = 0;
for(i = 0; i < getdtablesize; i++){
close(i);
}while(1)
{
//周期性的需要执行的进程
}
六、实例
创建一个守护进程,在time.log日志文件中每隔一秒,记录当前时间
代码如下:
/*===============================================================
* Copyright (C) 2022 All rights reserved.
*
* 文件名称:daemon.c
* 创 建 者:QiuCC
* 创建日期:2022年08月08日m *now_time;
* 描 述:
*
* 更新日志:
*
================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#define N 100
int main(int argc, char *argv[])
{
time_t now_sec;
struct tm *now_time;
int i, ret;
pid_t daemon_pid = -1;
//创建子进程
daemon_pid = fork();
if(daemon_pid < 0){
perror("Create daemon_pid");
return -1;
}
//判断父子进程
if(daemon_pid > 0){
exit(0);//杀死父进程,得到孤儿进程
}
setsid();//让子进程脱离原本回话
chdir("/tmp");//修改当前工作路径,之后打开文件必须给绝对路径,不然会写到/tmp下的time.log中
umask(0);//重设文件权限掩码
//删除进程中所有的文件描述符
for(i = 0; i < getdtablesize(); i++){
close(i);
}
printf("ok\n");
//周期性执行的目标进程
while(1){
time(&now_sec);
now_time = localtime(&now_sec);
FILE *fp = fopen("/home/qcc/Desktop/learn/04level/daemon/time.log", "a+");
if(NULL == fp){
perror("fopen");
exit(-1);
}
fprintf(fp, "%d年%d月%d日%d时%d分%d秒\n", now_time->tm_year+1900, now_time->tm_mon+1, now_time->tm_mday, now_time->tm_hour, now_time->tm_min, now_time->tm_sec);
//fflush(fp);
fclose(fp);
sleep(1);
}
return 0;
}
接下来我们运行以上代码
此时由于是后台进程,我们无法在前台看到执行过程,所以我们使用ps -ef查看进程号
此时我们可以看到我们的守护进程正在后台运行,并且PID号为4938,我们kill掉 ./a.out
接着我们ls查看当前目录,发现我们之前没有创建的time.log文件生成,我们进入发现信息都已经写入了,说明我们的守护进程创建成功!!!
好的,以上就是本期内容,欢迎大家参考指正!!!