1、进程状态和system函数
1.1、进程的5种状态
(1)就绪态。
这个进程当前所有运行条件就绪,只要得到了CPU时间就能直接运行。
(2)运行态。
就绪态时得到了CPU就进入运行态开始运行。
(3)僵尸态。
进程已经结束但是父进程还没来得及回收。
(4)等待态。
(浅度睡眠&深度睡眠),进程在等待某种条件,条件成熟后可进入就绪态。等待态下就算你给他CPU调度进程也无法执行。浅度睡眠等待时进程可以被(信号)唤醒,而深度睡眠等待时不能被唤醒,只能等待的条件到了才能结束睡眠状态。
(5)暂停态。
暂停并不是进程的终止,只是被人(信号)暂停了,还是可以恢复的。
1.2、进程各种状态之间的转换图
1.3、system函数简介
(1)system函数 = fork + exec
(2)原子操作
原子操作意思就是整个操作一旦开始就会不被打断的执行完。原子操作的好处就是不会被人打断(不会引来竞争状态),坏处是自己单独占用CPU时间太长,影响系统整体实时性,因此应该尽量避免不必要的原子操作,就算不得不进行原子操作,也应该尽量把原子操作的时间缩短。
2、进程关系
(1)无关系
(2)父子进程关系
(3)进程组(group):由若干进程构成的一个进程组。
(4)会话(session):会话就是进程组的组。
3、守护进程的引入
3.1、进程查看命令ps
(1)ps -ajx 偏向显示各种进程有关的ID号
(2)ps -aux 偏向显示进程各种占用资源
3.2、向进程发送信号指令kill
(1)kill -信号编号 进程ID,向一个进程发送一个信号
(2)kill -9 xxx,向xxx这个进程发送9号信号,也就是要结束进程。
3.3、何谓守护进程
(1)daemon,表示守护进程,简称为d(进程名后面带d的基本就是守护进程)。
(2)长期运行(一般是开机运行直到关机时关闭)。
(3)与控制台脱离(普通进程都和运行该进程的控制台相绑定,表现为如果终端被强制关闭了,则这个终端中运行的所有进程都会被关闭,背后的问题实质还在于会话(session))。
(4)服务器(Server),服务器程序就是一个一直在运行的程序,可以给我们提供某种服务(譬如nfs服务器给我们提供nfs通信方式),当我们程序需要这种服务时,我们就可以直接调用服务器程序(和服务器程序通信以得到服务器程序的帮助)老进行这种服务操作。服务器程序一般都实现为守护进程。
3.4、常见的守护进程
(1)syslogd,系统日志守护进程,提供syslog功能。
(2)cron,cron进程用来实现操作系统的时间管理,linux中实现定时执行程序的功能就要用到cron。
4、编写简单的守护进程
4.1、任何一个进程都可以将自己实现成守护进程
4.2、create_daemon函数要素
(1)子进程父进程退出。
(2)子进程使用seysid创建新的会话期,脱离控制台。
(3)调用chdir将当前工作目录设置为/
(4)umask设置为0,以取消任何文件权限屏蔽
(5)关闭所有文件描述符
(6)将0、1、2定位到/dev/null
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void creat_daemon(void);
int main(void)
{
creat_daemon();
while(1)
{
printf("I am running.\n");
sleep(1);
}
return 0;
}
//函数作用就是把调用该函数的进程变成一个守护进程
void creat_daemon(void)
{
pid_t pid = 0;
pid = fork(); //创建子进程
if(pid < 0)
{
//失败
perror("fork");
exit(-1);
}
if(pid > 0)
{
exit(-1); //父进程直接退出
}
//到这里就是子进程
//setsid将当前进程设置为一个新的会话期session,
//目的就是让当前进程脱离控制台。
pid = setsid();
if (pid < 0)
{
perror("setsid");
exit(-1);
}
//将当前进程工作目录设置为根目录
chdir("/");
//umask设置为0,确保将来进程有最大的文件操作权限
umask(0);
//关闭所有文件描述符
//先要获取当前系统打开的最大文件描述符的数目
int cnt = sysconf(_SC_OPEN_MAX);
int i = 0;
for(i=0; i<cnt; i++)
{
close(i);
}
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);
open("/dev/null",O_RDWR);
}
注:笔记整理记录于——《朱老师物联网大讲堂》—3.4linux进程全解