七、进程控制
$ ps axj
$ ps axj | grep xxxx
$ tail -f xxx
7.1 进程组
每个进程除了有一进程ID之外,还属于一个进程组,进程组是一个或多个进程的集合,进程组ID是一个正整数,并可以存放在pid_t数据类型中,getpgrp可以返回调用进程的进程组ID。
进程组:
作用:对相同类型的进程进行管理
进程组的诞生:
- 在shell里面直接执行一个应用程序,对于大部分进程来说,自己就是进程组的首进程。进程组只有一个进程
- 如果进程调用了fork函数,那么父子进程同属一个进程组,父进程为首进程
- 在shell中通过管道执行连接起来的应用程序,两个程序同属一个进程组,第一个程序为进程组的首进程
进程组id:pgid,由首进程pid决定
前台进程组:
shell进程启动时,默认是前台进程组的首进程。
前台进程组的首进程会占用会话所关联的终端来运行,shell启动其他应用程序时,其他程序成为首进程
后台进程组:
后台进程中的程序是不会占用终端
在shell进程里启动程序时,加上&符号可以指定程序运行在后台进程组里面
ctrl+z
jobs:查看有哪些后台进程组
fg+job id可以把后台进程组切换为前台进程组
7.2 会话
作用:管理进程组
会话的诞生:
- 调用setsid函数,新建一个会话,应用程序作为会话的第一个进程,称为会话首进程
- 用户在终端正确登录之后,启动shell时linux系统会创建一个新的会话,shell进程作为会话首进程
会话id:会话首进程id,SID
setsid():
函数功能:创建一个新的会话,在子进程调用,创建守护进程。
#include <sys/types.h>
#include <unistd.h>
pid_t setsid(void);
如果调用此函数的进程不是一个进程组的组长,则此函数创建一个新会话。具体会发生以下3件事。
该进程变成新会话的会话首进程( session leader,会话首进程是创建该会话的进程)。此时,该进程是新会话中的唯一进程。
该进程成为一个新进程组的组长进程。新进程组ID是该调用进程的进程ID.
该进程没有控制终端。如果在调用setsid之前该进程有一个控制终端,那么这种联系也被切断。
如果该调用进程已经是一个进程组的组长,则此函数返回出错。
7.3 终端
7.6
创建一个新的会话,
pid = gid
解释器就是一个二进制的可执行文件
八、守护进程
$ cd /var/log
$ tail if -xxx
13.3 理论 四个黑点
13.6
会话用来管理前后台进程组
会话一般关联着一个终端 当终端被关闭了之后,会话中的所有进程都会被关掉
守护进程特点:pid = pgid = sid
不受终端影响,就算终端退出,也可以继续在后台运行
守护进程的父进程是1号或者指定的某个进程
8.1 写一个守护进程
1.创建一 个子进程,父进程直接退出
方法:通过fork)函数
2.关闭不需要的文件描述符 0, 1, 2:标准输入、输出、出错
方法:通过dup2()函数
3.创建一个新的会话, 摆脱终端的影响
方法:通过setsid()函数
4.重设文件权限掩码新建文件的权限受文件权限掩码影响
umask:022,000010010,只写
新建文件默认执行权限: 666, 110110110
真正的文件执行权限:666&~umask
方法:通过umask)函数
5.改变守护进程的当前工作目录,改为"/"
方法:通过chdir)函数
创建守护进程代码实现:
void daemonize()
{
pid_t pid;
int fd;
pid = fork();
if(pid < 0)
{
syslog(LOG_ERR,"fork():%s",strerror(errno));
exit(0);
}
if(pid > 0)
exit(0);
fd = open("/dev/null",O_RDWR);
if(fd < 0)
{
syslog(LOG_WARNING,"open():%s",strerror(errno));
}
else
{
dup2(fd,0);
dup2(fd,1);
dup2(fd,2);
if(fd > 2)
close(fd);
}
setsid();
umask(0);
chdir("/");
}
日志的权限都比较高,为了避免秀改。
8.2 写一个日志文件
$ cd /var/log
$ vim /var/log/syslog
openlog() && closelog()
函数功能:此函数用来打开一个到系统日志记录程序的连接,
我们可以指定一个名称,以后, 这个名称将被加至每则记录消息中
void openlog(const char *ident, int option, int facility);
void closelog(void);
参数:
- ident:是一个标记,ident所表示的字符换将固定加在每行日志前面以标识这个日志,通常为程序的名称
- option:位图 LOG_PID(每一个信息都带着一个PID),man手册查看
- facility:再次更详细的说明一下你是谁
option | 描述 |
---|
LOG_PID | 每一个消息都加上用户的pid | LOG_CONS | 如果发送系统日志出现错误,将直接写入到系统控制台 | LOG_PERROR | 还要将消息记录到stderr. |
facility | 描述 |
---|
LOG_DAEMON | 设置守护进程没有单独的设备值 | LOG_CRON | 时钟守护进程 |
syslog()
函数功能:把日志消息发给系统程序syslog去记录
提交我也写的东西给要写日志的人(把要写的内容发送过去)。
void syslog(int priority, const char *format, ...);
参数:
- priorit:优先级别
- format:输出项 (注意:不能加 ‘\n’ )
priority | 描述 |
---|
LOG_ERR | 错误信息 | LOG_DEBUG | 级的调试信息 | | |
|