《UNIX环境高级编程》笔记--tcgetpgrp,tcsetpgrp和tcgetsid函数

需要有一种方法来通知内核哪一个进程组是前台进程,这样,终端设备驱动程序就能了解将终端输入和终端产生的信号送

到何处。

#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.

你可能感兴趣的:(《UNIX环境高级编程》笔记--tcgetpgrp,tcsetpgrp和tcgetsid函数)