需要有一种方法来通知内核哪一个进程组是前台进程,这样,终端设备驱动程序就能了解将终端输入和终端产生的信号送
到何处。
#include <unistd.h> pid_t tcgetpgrp(int filedes); //返回值:若成功则返回前台进程组的进程组ID,出错则返回-1. int tcsetpgrp(int filedes, pid_t pgrpid); //返回值:成功则返回0,出错则返回-1.函数tcgetpgrp返回前台进程组的进程组ID,该进程组与filedes上打开的终端相关联。
如果进程有一个控制终端,则该进程可以调用tcsetpgrp将前台进程组ID设置为pgrpid。pgrpid的值应当是在同一会话中的
一个进程组的ID,filedes必须引用该会话的控制终端。比如我们在执行fg命令时,就是shell调用tcsetpgrp函数将后台进程
改为前台进程。
给出控制tty的文件描述符,应用程序能获得会话首进程的进程组ID:
#include <termios.h> pid_t tcgetsid(int filedes); //若成功则返回会话首进程进程组ID,出错则返回-1.实践:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <termios.h> #include <fcntl.h> static void judge(void){ pid_t pid; pid = tcgetpgrp(STDIN_FILENO); if(pid == -1){ perror("tcgetpgrp"); return; }else if(pid == getpgrp()){ printf("foreground\n"); }else{ printf("background\n"); } } int main(void){ printf("tcgetsid:%d,pgrp=%d,sid=%d\n",tcgetsid(STDIN_FILENO),getpgrp(),getsid(getpid())); signal(SIGTTOU,SIG_IGN); judge(); int result; result = tcsetpgrp(STDIN_FILENO,getpgrp()); if(result == -1){ perror("tcsetpgrp"); return -1; } judge(); return 0; }运行1结果:
todd911@todd911-virtual-machine:~$ ./a.out &
[1] 17191
gmdz@gmdz-virtual-machine:~$ tcgetsid:16778,pgrp=17191,sid=16778
background
foreground
exit
一开始是后台运行的,所以是background,通过tcsetpgrp将进程修改为前台,通过程序获取状态为foreground,但是不明白为什么
会自动执行了exit。。如果有知道的大侠请告诉一下原因。。
感谢朽木可雕的在回复,该问题解决了:
修改后的程序如下:
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <termios.h> #include <fcntl.h> static void judge(void){ pid_t pid; pid = tcgetpgrp(STDIN_FILENO); if(pid == -1){ perror("tcgetpgrp"); return; }else if(pid == getpgrp()){ printf("foreground\n"); }else{ printf("background\n"); } } int main(void){ pid_t spid; printf("tcgetsid:%d,pgrp=%d,sid=%d\n",tcgetsid(STDIN_FILENO),getpgrp(),getsid(getpid())); spid = tcgetsid(STDIN_FILENO); signal(SIGTTOU,SIG_IGN); judge(); int result; result = tcsetpgrp(STDIN_FILENO,getpgrp()); if(result == -1){ perror("tcsetpgrp"); return -1; } judge(); result = tcsetpgrp(STDIN_FILENO,spid); return 0; }
原话如下:
因为你修改了控制终端给你的进程组,如果当前进程组没有进程则进程组生命周期结束,控制终端释放,所以在程序结束前
应该把控制终端还给原来的进程组。
为什么这边要处理SIGTTOU信号呢,请看下面man说明:
If tcsetpgrp() is called by a member of a background process group in
its session, and the calling process is not blocking or ignoring SIGT‐TOU,
a SIGTTOU signal is sent to all members of this background processgroup.