tgid vs pid
- Linux中并没有明确的线程支持
- Linux中的线程,即轻量级的进程
- 从内核角度,以线程为单位,一个线程对应一个task_struct,对应一个pid
- 从用户角度,以进程为单位,一个进程是多个线程组成的线程组,对应一个tgid(thread group id)
- ps/top指令,系统调用getpid()返回的是tgid(用户态)
- fork()派生进程,clone()派生线程,fork调用了clone()
task_struct
- 描述一个线程的信息
struct task_struct
{
//...
pid_t pid; //线程号
pid_t tgid; //领头线程号,即进程号
struct task_struct *group_leader; //领头线程
struct pid_link pids[PIDTYPE_MAX];
struct nsproxy *nsproxy;
//...
};
- group_leader:指向领头线程
- nsproxy:指向命名空间域。nsproxy域包含了五个不同类型(uts_namespace、ipc_namespace、mnt_namespace、pid_namspace、net)的命名空间指针
struct pid
- struct pid是内核对进程的PID的表示(与线程的pid_t pid区别)
- 一个struct pid可以对应多个task_struct,即一个进程包含多个线程
- 一个PID可以对应多个的命名空间(pid_namespace)
struct pid
{
atomic_t count;
/* 使用该pid的进程的列表, lists of tasks that use this pid */
struct hlist_head tasks[PIDTYPE_MAX];
int level;
struct upid numbers[1];
};
- count:是指使用该PID的线程(task)的数目
- level:该命名空间的层次信息
- tasks[PIDTYPE_MAX]:每个数组元素都是一个表头,存储同一类型的task_struct实例(参见task_struct的枚举类型成员:pid_type)
- numbers[1]:upid是特定命名空间可见的pid信息。保存了该进程的PID对不同命名空间的upid
struct upid
- upid是特定命名空间可见的pid信息
struct upid
{
/* Try to keep pid_chain in the same cacheline as nr for find_vpid */
int nr;
struct pid_namespace *ns;
struct hlist_node pid_chain;
};
- nr:局部id(存在特定命名空间下,父ns可以看见子ns的nr,反之不行)
- pid_namespace:指向与pid有关的命名空间
图与实例
- 多个task_struct指向一个PID
- PID的tasks数组里3个不同的task类型对task散列
- 一个PID会属于多个命名空间
参考:链接: link.