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;
}