进程间的关系:
进程间的关系除了有父子关系,还有组的关系。
进程组:一个或者多个进程的集合
进程组中有一个进程是组长进程,进程组id就等于这个进程的pid
进程组不会随着组长进程退出而退出,而是等组中的所有进程退出后才退出,进程组内即使只有一个进程了,组依然存在。
ctrl c 是使前台进程组退出(s+,前台 进程,s,没有+的是后台进程,指令后加个&,就变后台进程)
前台换后台 Ctrl z
后台换前台 fg xx(xx是作业序列号);
jobs 查看当前后台作业
bg 让后台作业运行起来
进程组和作业
进程组的创建时为了完成某项任务的,进程组通常和作业联系在一起,多个进程集合在协同完成一个任务就叫做作业。
一个终端下有两类作业的进程,前台和后台的,
一个终端前后台的控制不仅仅是进程组还有作业,前后台控制是通过作业和进程组完成的。
一个shell终端中,前台作业只有一个,而后台作业可以有多个
作业和进程组的区别:前台进程的子进程不属于前台作业,但父子进程却同属一个进程组。
会话:
当我们打开终端时,比如Linux(终端)或者xshell(伪终端),登录成功则创建了一个会话。在这个创建的会话中
在会话中输入指令时就是在创建作业。
可能会有一个终端,其中这个会话中有个会话首进程,这个进程是shell,这个进程将会话和终端练习起来
一个会话中有一个前台进程组和任意多个后台进程组
登录成功后,我们所运行的进程都是属于会话。
作业控制
shell可以同时运行一个前台和任意多的后台进程得说法是不全面的,事实上,shell分前后台来控制的不是进程而是作业或者进程组。这就是作业控制。
守护进程
守护进程也称精灵进程,是运行在后台的一种特殊进程。独立于终端且周期性地执行某种任务或者等待处理某些发生的事情,守护进程是一种很有用的进程,Linux大多数的服务器就是用守护进程实现的。守护进自成进程组,自成会话。它7不受用户登录注销的影响,在一直运行着。
前台进程和后台进程的区别:前台进程和用户交互,而后台进程基本上不和用户交互。
后台进程和守护进程的区别:后台进程受用户登录注销的影响。
ps axj | greap -E 'ds'; //查看守护进程
创建守护进程
创建接口:
//创建守护进程最关键的一步就是调用setsid函数创建一个新的会话(Session),并成为会话组组长(Session Leader)。
pid_t setsid(void);
//功能就是哪个进程调用它,就给哪个进程新建一个会话
成功返回新会话id,失败返回-1
//需要强调的是调用这个函数的当前进程不能是进程组的Leader,否则该函数返回-1。
//要保证当前进程不是进程组的Leader,只先fork在调用setsid就行,因为 父子进程再同一个进程组,进程组的Leader必然是该组的第一个进程,所以子进程不可能是leader进程,在子进程中调用setsid就不会出问题了。
//所以它是由孤儿进程创建的会话
调用成功的结果:
- 创建一个新的Session,当前进程成为Session Leader,当前进程的id就是Session的id。
- 创建一个新的进程组,当前进程成为进程组的Leader,当前 进程的id就是进程组id。
- 如果当前进程原本有一个控制终端,则它失去这个控制终端,成为一个没有控制终端的进程。
自己定义的守护进程的方法
1#include<stdio.h>
2 #include<unistd.h>
3 #include<sys/types.h>
4 #include<sys/stat.h>
5 #include<stdlib.h>
6 #include<signal.h>
7 void Mydaemon()
8 {
9
10 umask(0);
11 int pid = fork();
12 if(pid>0)
13 {
14 exit(0);
15 }
16 else if(pid<0)
17 {
18 exit(-1);
19 }
20 setsid();
chdir("/"); //改变当前路径为根目录
21 signal(SIGCHLD,SIG_IGN);//忽略子进程的退出信号
close(0);//关闭不需要的文件描述符
24 close(1);
25 close(2);
26
27
28 }
29
30
31
32 int main()
33 {
34 Mydaemon();
35 while(1)
36 {
37
38 }
39
40 return 0;
41 }
系统创建守护进程的接口
#include<inistd.h>
int daemon(int nochdir, intniclose);
参数:
是否改变当前路径,为0时 ,当前目录变为根目录;
是否关闭或重定向文件描述符他,为0时,重定向
int daemon(0,0);为0时 ,当前目录变为根目录;重定向标准文件描述符到文件黑洞 /dev/null
int daemon(1,1); //什么也不改变
#include<unistd.h>
int main()
32 {
33 daemon();
34 while(1)
35 {
36
37 }
38
39 return 0;
40 }