本文参考了:linux
task_struct
,用来保存task 状态。linux 内核中有一个包含全部 task 的链表,把全部的 task_struct 连起来。git
如图所示:github
struct 定义:docker
struct list_head tasks;
复制代码
看一下每一个task_struct
包含了哪些重要的字段。bash
和任务 ID 相关的字段有下面这些:数据结构
pid_t pid;
pid_t tgid;
struct task_struct *group_leader;
复制代码
这三个字段的具体含义为:工具
任何一个进程,若是只有主线程,那 pid 是本身,tgid 是本身,group_leader 指向的仍是本身。spa
可是,若是一个进程建立了其余线程,那就会有所变化了。线程有本身的 pid,tgid 就是进程的主线程的 pid,group_leader 指向的就是进程的主线程。操作系统
有了 tgid 以后,咱们就能够判断一个 task 是线程仍是进程了。线程
那么区分是进程仍是线程有什么用呢?考虑下面几个场景:
ps
命令ps
默认展现的是全部进程的列表,而不是把全部的线程都列出来,那会显得很乱没有重点。
kill -9
信号?假如说咱们给某个进程中的一个线程发送了退出信号(好比kill -9
),那么咱们不该该只退出这个线程,而是退出整个进程(至于为何请看下文)。因此就须要某种方式,可以获取该线程所在进程中全部线程的 pid。
从一个进程中杀死某一个线程是很是危险的操做。 好比说某个 thread正在进行分配内存的工做,这时候它会hold 内存分配器的 lock。若是你把它强制杀死了,这个锁就永远不会释放,那么其余的 thread 也会中止。因此须要主进程的协助,来优雅地退出全部的线程。
上图来源于 这个so 上的问答。
不信的话,咱们能够来作一个实验。
下图显示的是htop
工具,白色的表示进程,绿色的表示线程。能够看到每一个线程确实都有一个惟一的 PID。
如今让咱们来给图中标记的PID 为21656
的code-server
线程发送kill -9
信号,而后发现,整个进程都退出了:
上图中,code-server
这个 docker 容器进程在一分钟前退出了。
源代码地址:github.com/torvalds/li…
/* Signal handlers: */
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked;
sigset_t real_blocked;
sigset_t saved_sigmask;
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
unsigned int sas_ss_flags;
复制代码
注意这里的struct signal_struct *signal;
指向了一个signal
struct。这个struct 中还有一个struct sigpending pending;
。前面提到过须要区分线程和进程,这里也能够看出一点端倪。第一个是线程组共享的,一个是本任务的。
一个 task 的任务状态一共能够取下面的这些值:
/* Used in tsk->state: */
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
#define __TASK_STOPPED 4
#define __TASK_TRACED 8
/* Used in tsk->exit_state: */
#define EXIT_DEAD 16
#define EXIT_ZOMBIE 32
#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_DEAD 64
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
#define TASK_PARKED 512
#define TASK_NOLOAD 1024
#define TASK_NEW 2048
#define TASK_STATE_MAX 4096
复制代码
个人公众号:全栈不存在的