1.进程ID
线程组ID:
- 设置了CLONE_THREAD flag创建的进程(线程)同属于同一个线程组,拥有同一个线程组ID(TGID)。
- pthread_create创建线程的时候,底层通过clone函数实现就指定了CLONE_THREAD参数,即一个进程中的各个线程属于同一个线程组。
- 如果一个进程没有使用线程,则其PID=TGID。
- 线程组中的主进程叫组长(group leader)。Linux中task_struct结构体中的group_leader指向线程组组长。
进程组ID:
- 独立进程可以通过setpgrp合并成进程组。
- 进程组组长的PID即进程组ID。
- 管道连接的进程包含在同一个进程组中。
- 父进程和其子进程属于同一个进程组。
- 进程组组长进程退出,其他进程并不会因此退出。比如父进程退出,子进程不是必须退出。
2. 图解PID PPID PGID关系

getpid getpgid返回值的值:
父进程中调用:
getpid = 69485 getpgid = 69485
子进程中调用:
getpid = 69485 getpgid = 69485.
3.源码看进程的各种ID
分析进程相关的ID直接的过程是分析进程/线程创建的过程
fork.c::copy_process
    p->pid = pid_nr(pid);
    //指定CLONE_THREAD标志,新建进程的group_leaer就是当前进程的group_leader,tgid是当前进程的tgid
    //典型场景:pthread_create创建线程
    if (clone_flags & CLONE_THREAD) {
        p->exit_signal = -1;
        p->group_leader = current->group_leader;
        p->tgid = current->tgid;
    } else {
        //没有指定CLONE_THREAD,新建进程的group_leader指向新建进程的task_struct,tgid指向新建进程的pid.
        if (clone_flags & CLONE_PARENT)
            p->exit_signal = current->group_leader->exit_signal;
        else
            p->exit_signal = (clone_flags & CSIGNAL);
        p->group_leader = p;
        p->tgid = p->pid;
    }
    ...
    if (likely(p->pid)) {
        ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);
        //设置新建进程task_struct成员pids[PIDTYPE_PID]指向pid
        init_task_pid(p, PIDTYPE_PID, pid);
        if (thread_group_leader(p)) {
            //如果是线程组组长,设置新建进程task_struct成员pids[PIDTYPE_PGID]指向当前进程的pid.
            init_task_pid(p, PIDTYPE_PGID, task_pgrp(current));
            init_task_pid(p, PIDTYPE_SID, task_session(current));
            if (is_child_reaper(pid)) {
                ns_of_pid(pid)->child_reaper = p;
                p->signal->flags |= SIGNAL_UNKILLABLE;
            }
            p->signal->leader_pid = pid;
            p->signal->tty = tty_kref_get(current->signal->tty);
            list_add_tail(&p->sibling, &p->real_parent->children);
            list_add_tail_rcu(&p->tasks, &init_task.tasks);
            attach_pid(p, PIDTYPE_PGID);
            attach_pid(p, PIDTYPE_SID);
            __this_cpu_inc(process_counts);
        } else {
            current->signal->nr_threads++;
            atomic_inc(¤t->signal->live);
            atomic_inc(¤t->signal->sigcnt);
            list_add_tail_rcu(&p->thread_group,
                      &p->group_leader->thread_group);
            list_add_tail_rcu(&p->thread_node,
                      &p->signal->thread_head);
        }
        attach_pid(p, PIDTYPE_PID);
        nr_threads++;
    }内核ID相关函数:
//用户态gettid系统调用即该函数
static inline struct pid *task_pid(struct task_struct *task)
{
    return task->pids[PIDTYPE_PID].pid;
}
//用户态getpid系统调用即该函数
static inline struct pid *task_tgid(struct task_struct *task)
{
    return task->group_leader->pids[PIDTYPE_PID].pid;
}
/*
 * Without tasklist or rcu lock it is not safe to dereference
 * the result of task_pgrp/task_session even if task == current,
 * we can race with another thread doing sys_setsid/sys_setpgid.
 */
//用户态getpgid函数对应该函数
static inline struct pid *task_pgrp(struct task_struct *task)
{
    return task->group_leader->pids[PIDTYPE_PGID].pid;
}


















