Linux 內核101:進程數據結構

本文參考了:linux

基本概念清單

  • Linux 裏面,進程和線程到了內核,統一都叫作任務(Task)。
  • 每一個 task 都有一個數據接口task_struct,用來保存task 狀態。

任務列表

linux 內核中有一個包含全部 task 的鏈表,把全部的 task_struct 連起來。git

如圖所示:github

task_struct

struct 定義:docker

struct list_head		tasks;
複製代碼

看一下每一個task_struct包含了哪些重要的字段。bash

任務 ID

和任務 ID 相關的字段有下面這些:數據結構

pid_t pid;
pid_t tgid;
struct task_struct *group_leader; 
複製代碼

這三個字段的具體含義爲:工具

  • pid : 每一個 task 都有一個 pid,是惟一的,無論是進程仍是線程。
  • tgid: 指向主線程的 pid
  • 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 爲21656code-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

複製代碼

總結一下

個人公衆號:全棧不存在的

相關文章
相關標籤/搜索