需要有一种方法来通知内核哪一个进程组是前台进程,这样,终端设备驱动程序就能了解将终端输入和终端产生的信号送
到何处。
#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;
}
在tcsetpgrp之前需要将原来的控制全台进程组ID保存下来,程序结束前重新设置回该进程组ID。
原话如下:
因为你修改了控制终端给你的进程组,如果当前进程组没有进程则进程组生命周期结束,控制终端释放,所以在程序结束前
应该把控制终端还给原来的进程组。
为什么这边要处理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.