[APUE] 再读之进程关系


本章是最为难懂,最为晦涩的一章。主要讲解进程组,session, 终端,作业之间关系和概念。


1. 终端登录

终端登录由init自举fork getty进程,getty 调用类似execle("/usr/bin/login","login","-p",username,(char*)0,envp)这样的语句来完成登录过程。

正确登录后,login 就将当前工作目录更改为用户的起始目录(chdir),调用chown改变终端的所有权。调用setgid及initgroups设置进程的组ID。然后login所得到的所以信息初始化环境:起始目录,shell,用户名以及默认系统路径PATH,最后login 进程改变为登录用户的用户ID(setuid)并调用该用户的登录sheel.

execl("/bin/sh","-sh", (char*)0)

2. 进程组概念

#include 
#include 
pid_t getpgrp(void);
int setpgid(pid_t pid, pid_t pgid)
一个改变和设置组ID的例子

#include 
#include 
#include 

int main()
{
    pid_t pid;
    if((pid=fork())<0)
    {
        printf("fork error\n");
        return 1;
    }
    else if(pid==0)
    {
        printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
        sleep(3);
        setpgid(pid,pid);
        printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
    }
    else
    {
        printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
        if(wait(NULL)==-1)
        {
            printf("wait error\n");
        }
        printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
    }
}


3. session 概念

可以通过setsid来脱离原有session 创建新的session. 组长进程不能调用setsid,否则出错。调用后新session脱离原有控制终端。

setsid的一般会在创建精灵进程时被调用。


4. session ,控制终端和进程组关系

  • 一个session可以有一个控制终端,也可以一个没有
  • 建立与控制终端连接的对话期首进程,为控制终端
  • session中有一个前台进程组合若干个后台进程组
  • SIGINT和SIGQUIT将发送到所有前台进程
  • 如果终端界面检测到连接断开,将会发送挂断信号到控制进程

5. 孤儿进程组

父进程终止的进程组称为孤儿进程组。父进程终止后,子进程由init进程领养。父进程结束后,kernel 会向子进程发送SIGHUP 和SIGCONT信号。

下面demo,如果子进程不注册接收SIGHUP的signal 函数,那子进程将会被终止。

子进程试图读终端会失败。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
static void pr_ids(char* name)
{
    printf("%s: pid=%d, ppid=%d, pgid=%d\n",name, getpid(),getppid(),getpgrp());
    fflush(stdout);
}
static void sig_hup(int signo)
{
    printf("Received signal hup\n");
    return;
}
int main()
{
    pid_t pid;
    if((pid=fork())<0)
    {
        printf("fork error\n");
        exit(-1);
    }
    else if (pid>0) //parent
    {
        sleep(5);
        exit(0);
    }
    else
    {
        pr_ids("child");
        /*
        if (signal(SIGHUP,sig_hup)==SIG_ERR)
        {
            printf("signal error\n");
            return -1;
        }
        */
        kill(getpid(),SIGTSTP);
        pr_ids("child");
        char c;
        if(read(0,&c,1)!=1)
            printf("read error, errno =%d, reason=%s\n", errno, strerror(errno));
        exit(0);
    }
}




你可能感兴趣的:(笔记)