目录
一、什么是进程
二、进程的分类
三、如何关闭进程
四、进程相关接口函数
1、fork()
2、exit()
3、wait()
4、exec()
五、守护进程的创建
1、进程组的概念
2、会话
3、创建
(1)创建子进程,父进程退出,得到孤儿进程
(2)让子进程脱离原本会话
(3)修改当前工作路径(非必要,一般都会改)
(4)重设文件权限掩码(非必要,一般都会改)
(5)删除进程中所有的文件描述符(必须要操作)
六、实例
一、什么是进程
进程:即正在运行的程序。
二、进程的分类
前台进程:可以直接从当代终端使用ctrl+c退出的进程
后台进程:只能使用kill杀死或者其父进程结束后才会结束的进程
按如下代码举例:
#include#include #include #include #include #define N 100 int main(int argc, char *argv[]) { while(1){ printf("An"); 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
#include
pid_t fork(void);
返回值:
成功创建一个新的子进程,父进程返回子进程的PID号,子进程返回0
失败父进程返回-1,没有子进程被创建
2、exit()
#include
void exit(int status);
参数:
status:表示进程退出的状态
3、wait()
#include
#include
pid_t wait(int *wstatus);
参数:
wstatus:进程结束时,状态信息的首地址
返回值:
成功返回结束子进程的pid号,失败返回-1
4、exec()
#include
int execl(const char *pathname, const char *arg, ...);
参数:
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)
{
//周期性的需要执行的进程
}
六、实例
#include
#includepid_t fork(void);
返回值:
成功创建一个新的子进程,父进程返回子进程的PID号,子进程返回0
失败父进程返回-1,没有子进程被创建
2、exit()
#include
void exit(int status);
参数:
status:表示进程退出的状态
3、wait()
#include
#include
pid_t wait(int *wstatus);
参数:
wstatus:进程结束时,状态信息的首地址
返回值:
成功返回结束子进程的pid号,失败返回-1
4、exec()
#include
int execl(const char *pathname, const char *arg, ...);
参数:
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)
{
//周期性的需要执行的进程
}
六、实例
#include
void exit(int status);
参数:
status:表示进程退出的状态
#include
#includepid_t wait(int *wstatus);
参数:
wstatus:进程结束时,状态信息的首地址返回值:
成功返回结束子进程的pid号,失败返回-1
4、exec()
#include
int execl(const char *pathname, const char *arg, ...);
参数:
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)
{
//周期性的需要执行的进程
}
六、实例
#include
int execl(const char *pathname, const char *arg, ...);
参数:
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)
{
//周期性的需要执行的进程
}
六、实例
当用户执行了一个程序时,就相当于创建了一个进程组,跟该进程具有亲缘关系的所有进程都属于该进程组。
当用户打开一个终端时,就创建了一个会话,一个会话由一个或者多个进程组组成,一旦终端关闭,该会话中所有进程组中的进程全部结束。
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)
{
//周期性的需要执行的进程
}
六、实例
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)
{
//周期性的需要执行的进程
}
六、实例
setsid()
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)
{
//周期性的需要执行的进程
}
六、实例
umask(0);
getdtablesize()//获取最大的文件描述符
int i = 0;
for(i = 0; i < getdtablesize; i++){
close(i);
}while(1)
{
//周期性的需要执行的进程
}
六、实例
创建一个守护进程,在time.log日志文件中每隔一秒,记录当前时间
代码如下:
#include#include #include #include #include #include #include #include #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("okn"); //周期性执行的目标进程 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文件生成,我们进入发现信息都已经写入了,说明我们的守护进程创建成功!!!
好的,以上就是本期内容,欢迎大家参考指正!!!



