网站建设定金合同,天津seo方案,买花网站代码,wordpress主题修改字体一个进程组可以包含多个进程 进程组中的这些进程之间不是孤立的#xff0c;他们彼此之间或者存在者父子、兄弟关系#xff0c;或者在功能有相近的联系。 那linux为什么要有进程组呢#xff1f;其实提供进程组就是方便管理这些进程。假设要完成一个任务#xff0c;需要同时并… 一个进程组可以包含多个进程 进程组中的这些进程之间不是孤立的他们彼此之间或者存在者父子、兄弟关系或者在功能有相近的联系。 那linux为什么要有进程组呢其实提供进程组就是方便管理这些进程。假设要完成一个任务需要同时并发100个进程当用户由于 某种原因要终止这个任务时要是没有进程组就需要一个个去杀死这些进程设置了进程组之后就可以对进程组中的每个进程进行杀死。 每个进程必定属于一个进程组也只能属于一个进程组。 一个进程除了有进程ID外还有一个进程组ID每个进程组也有唯一的进程组ID。 每个进程组有一个进程组组长进程组组长的进程ID和组ID相同 函数getpgrp和getpgid可以返回调用进程的进程组ID #include unistd.h pid_t getpgrp(void); pid_t getpgid(pid_t pid); //返回值成功则返回进程组ID失败返回-1. 函数setpgid可以使进程加入现有的组或者创建一个新进程组。 #include unistd.h int setpgid(pid_t pid, pid_t pgid ); setpgid将pid进程的进程组ID设置为pgid. 1pidpgid 则表示将pid指定的进程设为进程组组长 2pid0 .则使用调用进程的进程ID
3pgid0,则将pid指定进程用作进程组ID。一个会话又可以包含多个进程组。一个会话对应一个控制终端 linux是一个多用户多任务的分时操作系统必须要支持多个用户同时登陆同一个操作系统当一个用户登陆一次终端时就会产生一个会话 每个会话有一个会话首进程即创建会话的进程建立与终端连接的就是这个会话首进程也被称为控制进程。一个会话可以包括多个进程组 这些进程组可被分为一个前台进程组和一个或多个后台进程组。为什么要这么分呢前台进程组是指需要与终端进行交互的进程组只能有一个 比如有些进程是需要完成IO操作的那么这个进程就会被设置为前台进程组.当我们键入终端的中断键和退出键时就会将信号发送到前台进程 组中的所有进程。而 后台进程组是指不需要与终端进程交互的进程组比如一些进程不需要完成IO 操作或者一些守护进程就会 被设置为后台进程组可以有多个 (这是我的理解不知道对错)。 如果终端接口检测到网络已经断开连接则会将挂断信号发送给会话首进程。 进程调用setsid函数建立一个新会话. #include unistd.h #include unistd.h pid_t setsid(pid_t pid); //返回成功则返回进程组ID失败则返回-1. 如果调用次函数的进程不是进程组的组长则会创建一个新会话结果将发生下面3件事情 1该进程会变为新会话的首进程。 2该进程会成为一个新进程组的组长进程 3该进程没有控制终端。 如果该调用进程已经是一个进程组的组长则调用会出错。 为了保证不会出错通常先fork一个子进程在关闭父进程因为子进程继承了父进程的进程组ID 而进程iD则是新分配的两者不可能相等从而保证了子进程不会是进程组组长。(后面编写守护进程时会用到。) 怎样编写守护进程 1. 在后台运行。 为避免挂起控制终端将Daemon放入后台执行。方法是在进程中调用fork使父进程终止让Daemon在子进程中后台执行。 if(pidfork()) exit(0);//是父进程结束父进程子进程继续 2. 脱离控制终端登录会话和进程组 有必要先介绍一下Linux中的进程与控制终端登录会话和进程组之间的关系进程属于一个进程组进程组号GID就是进程组长的进程号PID。登录会话可以包含多个进程组。这些进程组共享一个控制终端。这个控制终端通常是创建进程的登录终端。 控制终端登录会话和进程组通常是从父进程继承下来的。我们的目的就是要摆脱它们使之不受它们的影响。方法是在第1点的基础上调用setsid()使进程成为会话组长 setsid(); 说明当进程是会话组长时setsid()调用失败。但第一点已经保证进程不是会话组长。setsid()调用成功后进程成为新的会话组长和新的进程组长并与原来的登录会话和进程组脱离。由于会话过程对控制终端的独占性进程同时与控制终端脱离。 3. 禁止进程重新打开控制终端 现在进程已经成为无终端的会话组长。但它可以重新申请打开一个控制终端。可以通过使进程不再成为会话组长来禁止进程重新打开控制终端 if(pidfork()) exit(0);//结束第一子进程第二子进程继续第二子进程不再是会话组长 4. 关闭打开的文件描述符 进程从创建它的父进程那里继承了打开的文件描述符。如不关闭将会浪费系统资源造成进程所在的文件系统无法卸下以及引起无法预料的错误。按如下方法关闭它们 for(i0;i 关闭打开的文件描述符close(i); 5. 改变当前工作目录 进程活动时其工作目录所在的文件系统不能卸下。一般需要将工作目录改变到根目录。对于需要转储核心写运行日志的进程将工作目录改变到特定目录如/tmpchdir(/) 6. 重设文件创建掩模 进程从创建它的父进程那里继承了文件创建掩模。它可能修改守护进程所创建的文件的存取位。为防止这一点将文件创建掩模清除umask(0); 7. 处理SIGCHLD信号 处理SIGCHLD信号并不是必须的。但对于某些进程特别是服务器进程往往在请求到来时生成子进程处理请求。如果父进程不等待子进程结束子进程将成为僵尸进程zombie从而占用系统资源。如果父进程等待子进程结束将增加父进程的负担影响服务器进程的并发性能。在Linux下可以简单地将SIGCHLD信号的操作设为SIG_IGN。 signal(SIGCHLD,SIG_IGN); 这样内核在子进程结束时不会产生僵尸进程。这一点与BSD4不同BSD4下必须显式等待子进程结束才能释放僵尸进程。 daemontest.c #include stdio.h #include stdlib.h #include unistd.h #include sys/types.h #include sys/stat.h #include sys/param.h void init_daemon() { pid_t pid ; int i ; pid fork(); if(pid0) { printf(fork error secondly!\n); exit(1); } else if(pid0)//结束父进程 { printf(this is first parent process!\n); exit(0); }//子进程继续运行 setsid() ;//前面为setsid正确调用提供了前提使子进程成为新的会话组长和 //新的进程组长 pidfork(); if(pid0)//子进程成为无终端的会话组长但是还是可以打开终端为了 //使进程脱离终端使之成为不是会话组长 { printf( fork error secondly!\n); exit(1); } else if(pid0)//关闭第一个子进程 { printf(this is first child process!\n); exit(0); }//第二个子进程继续运行 for(i0;iNOFILE;i) { close(i); } chdir(/tmp); umask(0); return; } main.c #include stdio.h #include stdlib.h void init_daemon(void); int main(void) { FILE *fp ; init_daemon() ; while(1) { if((fpfopen(daemon.log,a))0) { fprintf(fp,%s,good); fclose(fp); sleep(10); } } exit(0); } 运行 yuanYUAN:~$ ./daemontest this is first parent process! this is first child process! yuanYUAN:~$ ps -axj 结果 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND 1 2970 2969 2969 ? -1 S 1000 0:00 ./daemontest