Linux 进程(二):进程关系及其守护进程
进程关系
进程组
进程组是一个或多个进程的集合。通常,它们是在同一作业中结合起来的,同一进程组中的各进程接收来自同一终端的各种信号,每个进程组有一个唯一的进程组ID。每个进程组有一个组长进程,该组长进程的ID等于进程组ID。从进程组创建开始到最后一个进程离开为止的时间称为进程组的生命周期。
|
#include <unistd.h> pid_t getpgrp(void); 返回值:调用进程的进程组ID int setpgid(pid_t pid, pid_t pgid); 返回值:成功,返回0;失败,返回-1 说明: setpgid用于添加进程到一个现有的进程组,或者创建一个新的进程组。 函数将进程ID为pid的进程加入ID为pgid的进程组中。 如果pid == pgid,则pid指定的进程变为进程组长; 如果pid == 0,则使用调用者的进程ID; 如果pgid == 0,则将pid用作进程组ID。 |
会话
会话是一个或者多个进程组的集合。进程组通常是由shell管道编制在一起的,如下:
|
proc1 | proc2 & proc3 | proc4 | proc5
|
进程调用setsid函数创建一个新的会话:
|
#include <unistd.h> pid_t setsid(void); 返回值:成功,返回进程组ID;失败,返回-1 说明: 如果调用此函的进程不是一个进程组长,则此函数创建一个新的会话,具体如下: (1) 该进程变为新会话的会话首进程。 (2) 该进程成为一个新进程组的组成进程,新进程组ID是该进程ID。 (3) 该进程没有控制终端。 pid_t getsid(pid_t pid); 返回值:成功,返回会话首进程的进程组ID;失败,返回-1 说明: getsid(0)返回调用进程的会话首进程的进程组ID,如果pid不属于调用者所在的会话,则不返回。 |
控制终端
一个会话可以有一个控制终端,通常是终端设备或伪终端设备。建立与控制终端连接的会话首进程被称为控制进程。一个会话中的进程组可被分为一个前台进程组和一个后台进程组。需要有一种方法通知内核哪一个进程组是前台进程组,这样便于终端设备驱动程序知道将终端输入和终端产生的信号发送到何处:
|
#include <unistd.h> pid_t tcgetpgrp(int fd); 返回值:成功,返回前台进程组ID;失败,返回-1 int tcsetpgrp(int fd, pid_pgrpid); 返回值:成功,返回0;失败,返回-1 说明: 其中,fd为相关联的打开终端。大多数应用程序并不直接调用这两个函数,而是由作业控制shell调用。 需要管理控制终端的应用程序可以调用tcgetsid函数获得控制终端的会话首进程的进程组ID: #include <termios.h> pid_t tcgetsid(int fd); 返回值:成功,返回会话首进程的进程组ID;失败,返回-1 |
作业控制
作业控制允许在一个终端上启动多个作业(进程组),哪一个作业可以访问该终端以及哪些作业在后台运行。从shell使用作业控制的角度看,用户可以在前台或者后台启动一个作业,例如:
vi main.c在前台启动只有一个进程组成的作业,而make all &在后台启动只有一个进程组成的作业。
我们可以键入3个特殊字符使得终端程序产生信号,并将它们发送到前台进程组:
中断字符(Ctrl + C)产生SIGINT信号;
退出字符(Ctrl + \)产生SIGQUIT信号;
挂起字符(Ctrl + Z)产生SIGTSTP信号;
只有前台作业才可以接收终端上输入的字符,如果后台作业试图都终端,那么终端驱动程序向后台作业发送特定信号SIGTTIN,该信号将停止此后台作业,而shell则向用户发送通知,然后用户就可以利用shell命令fg将此作业转为前台作业运行。但是如果后台作业输出到控制终端又将发生什么呢?我们可以通过stty命令禁止这种情况。此时,终端驱动程序向后台作业发送SIGTTOU信号,使其进程阻塞,当然此时我们也可以利用fg将其移到前台运行。
守护进程
守护进程(daemon)常常在系统引导装入时启动,在系统关闭时终止。由于守护进程没有控制终端(其终端名设置为?),因此,其在后台运行。大多守护进程都以超级用户权限执行。
编程规则
(1) 首先调用umask将文件模式创建屏蔽字设置为一个已知数值(通常是0)。这样做是防止继承而来的屏蔽字没有某些权限,尤其是写权限。
(2) 调用fork,然后使父进程exit。
(3) 调用setsid创建一个新会话。
(4) 将当前工作目录更改为根目录。因为守护进程通常在系统引导之前就存在,如果守护进程的当前工作目录在一个需要挂载的文件系统上,那么该文件系统不能被卸载。也有某些守护进程会把当前工作目录更改到某个指定的位置,例如行式打印机假脱机守护进程就可能将其工作目录更改到它们的spool目录上。
(5) 关闭不再需要的文件描述符。可以使用open_max函数或者getrlimit函数获取最高文件描述符值,然后关闭直到该值的所有文件描述符。这样做可以避免守护进程从其父进程继承任何文件描述符。
(6) 某些守护进程将文件描述符0、1、2指向/dev/null。这样可以使得任何以恶搞试图读标准输入、写标准输出、写标准错误输出的程序不产生任何效果。由于守护进程是在后台运行的,因此登录会话的终止并不影响守护进程。如果其他用户在同一终端设备上登录,我们自然不希望在该终端上见到守护进程的输出,用户也不希望他们在终端上的输入被守护进程读取,因此上述措施是相当有用的。
如下程序可由想要初始化为守护进程的程序调用,在main函数中调用函数daemonize,然后使main进程进入休眠状态,通过ps –efj命名查看进程状态,可以发现守护进程init,其终端名为 ?。
[root@benxintuzi process]# cat init.c
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/resource.h> void daemonize(const char *cmd)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa; /*
* * Clear file creation mask.
* */
umask(); /*
* * Get maximum number of file descriptors.
* */
if (getrlimit(RLIMIT_NOFILE, &rl) < )
{
printf("%s: can't get file limit\n", cmd);
return ;
} /*
* * Become a session leader to lose controlling TTY.
* */
if ((pid = fork()) < )
{
printf("%s: can't fork\n", cmd);
return ;
}
else if (pid != ) /* parent */
exit();
setsid(); /*
* * Ensure future opens won't allocate controlling TTYs.
* */
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = ;
if (sigaction(SIGHUP, &sa, NULL) < )
{
printf("%s: can't ignore SIGHUP\n", cmd);
return ;
}
if ((pid = fork()) < )
{
printf("%s: can't fork\n", cmd);
return ;
}
else if (pid != ) /* parent */
exit(); /*
* * Change the current working directory to the root so
* * we won't prevent file systems from being unmounted.
* */
if (chdir("/") < )
{
printf("%s: can't change directory to \n", cmd);
} /*
* * Close all open file descriptors.
* */
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = ;
for (i = ; i < rl.rlim_max; i++)
close(i); /*
* * Attach file descriptors 0, 1, and 2 to /dev/null.
* */
fd0 = open("/dev/null", O_RDWR);
fd1 = dup();
fd2 = dup(); /*
* * Initialize the log file.
* */
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != || fd1 != || fd2 != ) {
syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
fd0, fd1, fd2);
exit();
}
} int main(void)
{
daemonize("ps");
sleep();
return ;
} [root@benxintuzi process]# ./init
[root@benxintuzi process]# ps -efj
UID PID PPID PGID SID C STIME TTY TIME CMD
root : ? :: /sbin/init
root : pts/ :: vim init.c
root 2237 1 2236 2236 0 19:45 ? 00:00:00 ./init
root : pts/ :: ps -efj
Linux 进程(二):进程关系及其守护进程的更多相关文章
- linux系统编程之进程(八):守护进程详解及创建,daemon()使用
一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...
- (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- Linux 的进程组、会话、守护进程
一.进程组ID 每个进程都属于一个进程组.每个进程组有一个领头进程.进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号.每个进程组都有唯一的进程组ID(整数,也可以 ...
- linux第1天 fork exec 守护进程
概念方面 文件是对I/O设备的抽象表示.虚拟存储器是对主存和磁盘I/O设备的抽象表示.进程则是对处理器.主存和I/O设备的抽象表示 中断 早期是没有进程这个概念,当出现中断技术以后才出现进程这个概念 ...
- Linux系统编程(26)——守护进程
Linux系统启动时会启动很多系统服务进程,比如inetd,这些系统服务进程没有控制终端,不能直接和用户交互.其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户 ...
- linux c语言学习笔记之守护进程
哈尔滨理工大学软件工程专业08-7李万鹏原创作品,转载请标明出处 http://blog.csdn.net/woshixingaaa/archive/2010/06/06/5651095.aspx 守 ...
- Python之路(第三十七篇)并发编程:进程、multiprocess模块、创建进程方式、join()、守护进程
一.在python程序中的进程操作 之前已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序 ...
- 浅析linux 下shell命令执行和守护进程
执行shell脚本有以下几种方式 1.相对路径方式,需先cd到脚本路径下 [root@banking tmp]# cd /tmp [root@banking tmp]# ./ceshi.sh 脚本执行 ...
- Linux+Nginx+Asp.net Core及守护进程部署
上篇<Docker基础入门及示例>文章介绍了Docker部署,以及相关.net core 的打包示例.这篇文章我将以oss.offical.site站点为例,主要介绍下在linux机器下完 ...
随机推荐
- 关于 -webkit-line-clamp 详解
最近需要做个商品列表,在手机屏幕不太一样的市场里,如何做到列表中刚刚好显示2行,偶然间发现淘宝的手机版有用到-webkit-line-clamp来实现这种效果 限制在一个块元素显示的文本的行数. -w ...
- jquery遍历数组的方式
1,for循环: var arr = new Array(13.5,3,4,5,6); for(var i=0;i<arr.length;i++){ arr[i] = arr[i]/2.0; } ...
- Log4Net 最最最基本的应用。作为个人记录
本文只记录了将日志按照日期记录到文件中的方法. 注:1.如果将该方法封装在类库中,在引用类库的项目中添加配置文件. 2.如果程序为控制台程序.winfrom程序,需将配置文件存放在/bin/debug ...
- C++语言基础(17)-运算符重载
运算符重载的格式为: 返回值类型 operator 运算符名称 (形参表列){ //TODO: } 一.在类里面实例运行符重载 #include <iostream> using name ...
- C语言基础(16)-指针
一.指针的相关概念 1.1 指针变量 指针是一个变量,存放的是一个地址,该地址指向一块内存空间. 例: ; int *p = &a; // 定义一个指针变量p,&符号可以取得一个变量在 ...
- Tomcat闲聊第二话
windows下安装Tomcat可以直接下载Installer,需要注意的是,先确保安装了Java虚拟机. 注:默认安装路径为 C:\Program Files\Apache Software Fou ...
- swoole-1.7.18 版本已发布,支持 PHP7
swoole-1.7.18 版本已发布,支持 PHP7 matyhtf 发布于: 2015年07月23日 (22评) 分享到: 收藏 +16 3月19日,深圳源创会火热报名中,go>> ...
- PHP 7安装使用体验,升级PHP要谨慎
一.发挥PHP 7高性能的几个要点 PHP 7相对于之前的PHP版本来说可以说性能有了质的飞跃,但是所谓“好马配好鞍,好车配风帆”,想要发挥PHP 7的性能优势,还需要从以下几个方面做准备:(此部分引 ...
- apache下用expires_module让浏览器缓存静态文件
让浏览器缓存CSS.JS.图片.静态文件等是很重要的事情,这样可以减轻服务器的压力,省的浏览器经常要去服务端下载这些静态文件.下面看看配置方法吧. 1.开启apache扩展模块mod_expires. ...
- jquery中Uncaught TypeError: $(...).ajaxUpload is not a function(…)错误解决方法
错误原因:该函数不是jquery的核心函数,所以需要外部引入ajaxfileupload.js文件,可能是没有引入,或者引入的js文件互相冲突 解决方法:每次进入一个函数之前打印该函数所有的js文件, ...
