进程关系

进程组

进程组是一个或多个进程的集合。通常,它们是在同一作业中结合起来的,同一进程组中的各进程接收来自同一终端的各种信号,每个进程组有一个唯一的进程组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 进程(二):进程关系及其守护进程的更多相关文章

  1. linux系统编程之进程(八):守护进程详解及创建,daemon()使用

    一,守护进程概述 Linux Daemon(守护进程)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.它不需要用户输入就能运行而且提供某种服务,不是对整个 ...

  2. (七) 一起学 Unix 环境高级编程(APUE) 之 进程关系 和 守护进程

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  3. Linux 的进程组、会话、守护进程

    一.进程组ID 每个进程都属于一个进程组.每个进程组有一个领头进程.进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号.每个进程组都有唯一的进程组ID(整数,也可以 ...

  4. linux第1天 fork exec 守护进程

    概念方面 文件是对I/O设备的抽象表示.虚拟存储器是对主存和磁盘I/O设备的抽象表示.进程则是对处理器.主存和I/O设备的抽象表示 中断 早期是没有进程这个概念,当出现中断技术以后才出现进程这个概念 ...

  5. Linux系统编程(26)——守护进程

    Linux系统启动时会启动很多系统服务进程,比如inetd,这些系统服务进程没有控制终端,不能直接和用户交互.其它进程都是在用户登录或运行程序时创建,在运行结束或用户注销时终止,但系统服务进程不受用户 ...

  6. linux c语言学习笔记之守护进程

    哈尔滨理工大学软件工程专业08-7李万鹏原创作品,转载请标明出处 http://blog.csdn.net/woshixingaaa/archive/2010/06/06/5651095.aspx 守 ...

  7. Python之路(第三十七篇)并发编程:进程、multiprocess模块、创建进程方式、join()、守护进程

    一.在python程序中的进程操作 之前已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起来的python程序 ...

  8. 浅析linux 下shell命令执行和守护进程

    执行shell脚本有以下几种方式 1.相对路径方式,需先cd到脚本路径下 [root@banking tmp]# cd /tmp [root@banking tmp]# ./ceshi.sh 脚本执行 ...

  9. Linux+Nginx+Asp.net Core及守护进程部署

    上篇<Docker基础入门及示例>文章介绍了Docker部署,以及相关.net core 的打包示例.这篇文章我将以oss.offical.site站点为例,主要介绍下在linux机器下完 ...

随机推荐

  1. 利用forever在Linux上实现Node.js项目自启动

    在一台计算机上手动跑Node项目简单,node xx.js就搞定了,想让Node项目后台执行,尽管不能直接用node命令搞定,可是在安装了forever这个包以后.还是非常轻松的.只是要是在远程ser ...

  2. LINUX经常使用命令小整理

    系统操作: 1.重新启动机器:reboot. 2.查看某程序的进程:ps -ef|grep xxx(比如:ps -ef|grep tomcat). 3.查看当前linux系统系统版本号:lsb_rel ...

  3. BZOJ 1016 JSOI 2008 最小生成树计数 Kruskal+搜索

    题目大意:给出一些边,求出一共能形成多少个最小生成树. 思路:最小生成树有非常多定理啊,我也不是非常明确.这里仅仅简单讲讲做法.关于定各种定理请看这里:http://blog.csdn.net/wyf ...

  4. 【Dos】Dos命令大全

    dos命令大全 AT 计划在计算机上运行的命令和程序.ATTRIB 显示或更改文件属性.BREAK 设置或清除扩展式 CTRL+C 检查.CACLS 显示或修改文件的访问控制列表(ACLs).CALL ...

  5. c与c++中的强制类型转换区别

    强制类型转换的一般形式为: (类型名)(表达式) 如:(int)a.这是C语言使用的形式,C++把它保留了下来,以利于兼容. C++还增加了以下形式: 类型名(表达式) 如:int(a).这种形式类似 ...

  6. Oculus rift development kit 2使用手记(2014年10月到货)

    昨天上午拿到后就立即拆包体验. 首先说下配置流程,其实很简单: 第一步是下载runtime,在没插dk2的时候安装好runtime. 第二步看着说明书(有图解)把硬件连接完毕.这里要说明的是dk2默认 ...

  7. laravel框架查看执行过的sql语句

    1.在routes.php中添加如下语句 Event::listen('illuminate.query', function($sql,$param) {     file_put_contents ...

  8. robot.txt 文件 作用和语法

    seo工作者应该不陌生,robots.txt文件是每一个搜索引擎蜘蛛到你的网站之后要寻找和访问的第一个文件,robots.txt是你对搜索引擎制定的一个如何索引你的网站的规则.通过该文件,搜索引擎就可 ...

  9. 606. Construct String from Binary Tree 【easy】

    606. Construct String from Binary Tree [easy] You need to construct a string consists of parenthesis ...

  10. iOS开发-常用第三方开源框架介绍

    iOS开发-常用第三方开源框架介绍 图像: 1.图片浏览控件MWPhotoBrowser        实现了一个照片浏览器类似 iOS 自带的相册应用,可显示来自手机的图片或者是网络图片,可自动从网 ...