内容简介:linux 内核中有一个包含所有 task 的链表,把所有的 task_struct 连起来。如图所示:struct 定义:
linux 内核中有一个包含所有 task 的链表,把所有的 task_struct 连起来。
如图所示:
task_struct
struct 定义:
struct list_head tasks; 复制代码
看一下每个 task_struct
包含了哪些重要的字段。
任务 ID
和任务 ID 相关的字段有下面这些:
pid_t pid; pid_t tgid; struct task_struct *group_leader; 复制代码
这三个字段的具体含义为:
- pid : 每个 task 都有一个 pid,是唯一的,不管是进程还是线程。
- tgid: 指向主线程的 pid
- group_leader: 指向进程的主线程
任何一个进程,如果只有主线程,那 pid 是自己,tgid 是自己,group_leader 指向的还是自己。
但是,如果一个进程创建了其他线程,那就会有所变化了。线程有自己的 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; 复制代码
- blocked : 被阻塞暂不处理
- pending : 等待处理
- sighand : 哪个信号正在被处理
注意这里的 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 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- linux内核数据结构之kfifo
- 从文件系统的数据结构看 Linux 内核设计
- 数据结构 – 用于构建文件系统的数据结构?
- 荐 用Python解决数据结构与算法问题(三):线性数据结构之栈
- 内核必须懂(六): 使用kgdb调试内核
- 数据库索引背后的数据结构
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。