DAY17-进程复习02

关注公众号:百万年薪工程师成长手札

进程的关键属性

pid

该字段保存了进程唯一的标识符,称为pid。Linux的PID是pid_t 整数类型。通过/proc/sys/kernel/pid_max接口制定,默认值为32768,最高可设置为2的22次方(PID_MAX_LIMIT, 约400万)

配置pid的linux源码在linux/include/threads.h下

/*
 * This controls the default maximum pid allocated to a process
 */
#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000)

从PID_MAX_DEFAULT 可以看出如果编译内核时设置了CONFIG_BASE_SMALL选项,则默认值为0x1000,转化成十进制为4096,否则默认值为0x8000,转化为十进制为32768

#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \
    (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT))

PID_MAX_LIMIT则是限制pid的上限,如果编译内核时设置了CONFIG_BASE_SMALL选项,则最大值就是 8 * PAGE_SIZE个大小,否则就看long数据类型的的大小,如果大于4,则最大可以设置4 * 1024 * 1024个(4194304个),否则最大值只能设置PID_MAX_DEFAULT。

从实际操作来看,符合代码的设置,pid_max最高不能超过4194304个。一般一个虚拟机,400w个pid也足够用了,一个虚拟机一般也就4C-8C,如果超过了400w个pid,可能就是应用的bug了,有进程或者线程泄漏。

另外在源码注释中有一段描述

[NOTE: PID/TIDs are limited to 2^29 ~= 500+ million, see futex.h.]

我把futex.h翻了半天,顺便百度了几次,也没有看到类似的代码段,不过从400万突破到500万,在大多数场景下意义不大,那就暂时不研究了。等以后C语言学的精通了,回过头来再研究。

pid的管理采用的是bitmap位图管理,该位图允许内核跟踪PID的使用情况,并为新进程分配唯一的pid。在位图中,值为1表示该pid已经被分配,值为0表示pid为空闲可分配。

tgid

该字段保存了线程组id。假设创建了一个新进程,他的pid和tgid是一样的。当进程产生一个新的线程时,新的子进程将获得唯一的pid,但是继承了父线程的tgid,因为属于同一个线程组。tgid用于支持多线程进程。

thread info

该字段保存了处理器特定的状态信息。并且他是任务结构体的关键元素

flags

该标志字段记录了进程响应的各种属性。该字段中的每一位对应于一个进程生命周期中的各个阶段。每个进程标志定义在中

/*
 * Per process flags
 */
#define PF_IDLE         0x00000002  /* I am an IDLE thread */
#define PF_EXITING      0x00000004  /* Getting shut down */
#define PF_VCPU         0x00000010  /* I'm a virtual CPU */
#define PF_WQ_WORKER        0x00000020  /* I'm a workqueue worker */
#define PF_FORKNOEXEC       0x00000040  /* Forked but didn't exec */
#define PF_MCE_PROCESS      0x00000080      /* Process policy on mce errors */
#define PF_SUPERPRIV        0x00000100  /* Used super-user privileges */
#define PF_DUMPCORE     0x00000200  /* Dumped core */
#define PF_SIGNALED     0x00000400  /* Killed by a signal */
#define PF_MEMALLOC     0x00000800  /* Allocating memory */
#define PF_NPROC_EXCEEDED   0x00001000  /* set_user() noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH        0x00002000  /* If unset the fpu must be initialized before use */
#define PF_USED_ASYNC       0x00004000  /* Used async_schedule*(), used by module init */
#define PF_NOFREEZE     0x00008000  /* This thread should not be frozen */
#define PF_FROZEN       0x00010000  /* Frozen for system suspend */
#define PF_KSWAPD       0x00020000  /* I am kswapd */
#define PF_MEMALLOC_NOFS    0x00040000  /* All allocation requests will inherit GFP_NOFS */
#define PF_MEMALLOC_NOIO    0x00080000  /* All allocation requests will inherit GFP_NOIO */
#define PF_LESS_THROTTLE    0x00100000  /* Throttle me less: I clean memory */
#define PF_KTHREAD      0x00200000  /* I am a kernel thread */
#define PF_RANDOMIZE        0x00400000  /* Randomize virtual address space */
#define PF_SWAPWRITE        0x00800000  /* Allowed to write to swap */
#define PF_MEMSTALL     0x01000000  /* Stalled due to lack of memory */
#define PF_UMH          0x02000000  /* I'm an Usermodehelper process */
#define PF_NO_SETAFFINITY   0x04000000  /* Userland is not allowed to meddle with cpus_mask */
#define PF_MCE_EARLY        0x08000000      /* Early kill for mce process policy */
#define PF_MEMALLOC_NOCMA   0x10000000  /* All allocation request will have _GFP_MOVABLE cleared */
#define PF_IO_WORKER        0x20000000  /* Task is an IO worker */
#define PF_FREEZER_SKIP     0x40000000  /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK     0x80000000      /* This thread called freeze_processes() and should not be frozen */

exit_code和exit_sigal

这些字段保存了任务的退出值和导致终止的信号的详细信息。这些字段将由父进程在子进程终止时通过wait()访问

comm

该字段保存了用于启动进程的二进制可执行文件的名称

ptrace

当使用ptrace()系统调用使进程转为跟踪模式时,将启用并设置该字段

进程关系

real_parent和parent

指向付任务结构体的指针。对于正常的进程,两个指针都指向同一个task_struct。他们的区别仅在于使用posix线程实现的多线程进程。对于这种,real_parent指向父线程任务结构体,parent指向收到SIGCHLD信号的进程任务结构体

children

指向子任务结构体链表的指针

sibling

指向兄弟任务结构体链表的指针

group_leader

指向进程组组长的任务结构体

调度属性

所有相互竞争的进程都必有公平的CPU时间,需要基于时间片和进程优先级来调度

prio和static_prio

prio确认调度进程的优先级。如果进程被分配了试试调度策略,则此字段保存进程的静态优先级,范围为1--99(由sched_setscheduler()指定)。对于正常进程,这个字段保存了由nice值得来的动态优先级。

se、rt和dl

每个任务都属于调度实体(任务组),因为调度是在每个实体级别上完成的。se用于所有正常进程,rt用于实时进程,dl用于截止期进程。

policy

该字段保存了和进程调度策略相关的信息,有助于确定进程优先级。

cpus_allowed

该字段指定了进程的CPU掩码。在多处理系统中,进程允许在哪个CPU上进行调度。(传统CPU使用4位掩码,如0000, 0001, 如果有超线程技术,则使用8位掩码)。

rt_priority

该字段用于指定实时调度策略的进程优先级。但对于非实时进程,该字段未被使用

内核栈

在基于多核硬件的当代计算平台上,可以同时并行运行应用程序。在请求同一个进程时,可以同时启动多个进程的内核模式切换。为了能够处理这种情况,内核服务被设计为可重入的,允许多个进程介入并使用所需的服务。这就要求请求进程维护他自己的私有内核栈,来跟踪内核函数调用顺序,存储内核函数的本地数据等等。

内核栈直接映射到物理内存,强制排列在物理上处于连续的区域中。在64位系统上为16KB内核栈

Linux线程支持

一个进程中的执行流被称为线程(thread),多线程意味着一个进程中存在多个执行上下文流。实现真正并发,公平的多任务处理。

Linux不直接支持用户级线程,它通过一个替代API枚举并成为轻量级进程(Light Weight Process, LWP)的特殊进程,该进程可以与父进程共享一组配置资源,例如动态内存分配、全局数据、打开文件、信号处理等。

内核线程

为满足运行后台操作的需要,内核会创建线程,内核线程没有地址空间,只在内核模式下运行,不具有交互性。内核子系统使用kthread线程周期性运行和进行异步操作。

所有的内核线程都是PID 2(kthreadd)的后代,

PPID为2

 

 

kthread是一个永久运行的线程,它会查看名为kthread_create_list的链表,用来获取要创建的新kthreads线程的数据

命名空间和cgroup

基于cgroup和命令空间的框架,可以给客户端提供高效和有效的隔离和资源管理

挂载命名空间

使文件系统挂载点的集合限制在一个进程的命名空间内可见,不同挂载命名空间中的进程组拥有不同的视图

UTS命令空间

一个uts命名空间能够隔离系统的主机和域名

IPC命名空间

将进程与使用system v和posix消息队列区分开来,防止一个进程从IPC命名空间访问另一个进程资源

PID命名空间

PID命名空间允许进程使用其自己的根进程。

网络命名空间

提供了网络协议服务和接口的抽象化和虚拟化。每个网络命名空间有自己的网络设备实例,可以使用单独的网络地址进行配置

用户命名空间

允许进程在命名空间内外使用唯一的用户id和组id。

cgroup命名空间

cgroup命名空间虚拟化/proc/self/cgroup问价的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值