1.进程标识描述

1.1标识ID

TID:每一个线程唯一的标识,系统最小的执行单位
PID:每一个进程唯一的标识,系统最基本的分配资源单位,PID是在一组
PPID:每一个进程的会携带父进程的PID,能清楚知道每个进程的层次关系
PGID:一堆“进程”组合而形成的集合,该集合叫进程组。每组会有一个领头羊的进程,该进程PID则是PGID
SID: 一堆”进程组“而形成的集合,该集合叫会话。

1.2标识作用

PGID和SID在默认情况,创建进程时,会默认继承父进程所在进程组和会话。
它们俩方便用于作业控制,SID在用户登录时由shell产生的首个进程PID,它作用于登录的整个生命周期内,包括用户所有活动行为。进程组是在会话作用下,由一系列的命令关联起来形成进程组,从而完成一项任务。

2.层次关系

画了一幅简单、规整、清晰的进程层次图。
以公司架构来描述容易理解,每一个process都携带一个线程(为了整体清晰,只把小组部分给展开了)。

集团由多个子公司独立运营而组成,在集团资金资助下,每个子公司会划分为多个部门,互相协作、共同发展;部门会以不同项目而细分不同小组,小组中由多个不同职位的成员负责项目的每一块的业务。成员作为最小执行单位,推动项目进展等。

从图中一个进程可以由多个线程组成,在同一个进程中的N个线程都是共享同一资源的;其中有一个线程TID和进程的PID是相同的,无论是小组/部门/子公司都需要至少一位成员担任领头羊,所以会出现相同的现象。

3.Linux系统层面

3.1 PID_TYPE类型

enum pid_type
{PIDTYPE_PID,PIDTYPE_TGID,PIDTYPE_PGID,PIDTYPE_SID,PIDTYPE_MAX,
};A struct pid is the kernel's internal notion of a process identifier.一个PID结构体是内核中的进程标识概念。It refers to individual tasks, process groups, and sessions.它指的是单个进程、进程组、会话。

3.2 PIDTYPE_TGID => pid

该类型就是进程的pid标识,由fork、vfork、clone等系统调用来创建新进程以及分配唯一的pid(命名空间内唯一)。在内核空间中是直接将由_do_fork函数处理的。

在用户空间获取pid的getpid函数,我们可以发现使用PIDTYPE_TGID获取进程pid,可以通过(层次关系)得知,pid本质就是进程的领头羊的tid。

3.3 PIDTYPE_PID => tid

在用户空间获取tid的gettid函数,代表每个执行单位的标识以及最基本的标识。其它ID标识(进程\进程组\会话)都是以tid作为自身进行描述。

注意:glibc库中没实现gettid函数,所以在linux系统中不能直接调用。直接调用syscall函数带上对应ID。

3.4 PIDTYPE_PGID => pgid

在用户空间获取pgid的getpgid函数,可以获取进程是属于哪一个进程组。形成进程组后,发送信号整个组内的进程都会收到。

3.5 PIDTYPE_SID -> sid

在用户空间获取sid的getsid函数,可以获取进程是属于哪一个会话。

3.6 标识的产生

上述的进程标识,会在_do_fork函数处理产生;任何方式创建进程\线程都会通过_do_fork函数。
_do_fork函数主要做三件事:创建进程/线程及分配资源(copy_process)、确定PID(pid_vnr)、加入调度模块的队列(wake_up_new_task)

函数原型
long _do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr,unsigned long tls)

clone_flags 需要复制/共享哪些资源
stack_start 用户空间的栈地址
stack_size 用户空间的栈大小
parent_tidptr/child_tidptr 指向用户空间的地址,内容为父/子进程PID
tls 设置线程的本地存储区,依赖于体系结构

/**  Ok, this is the main fork-routine.** It copies the process, and if successful kick-starts* it and waits for it to finish using the VM if required.*/
long _do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr,unsigned long tls)
{...struct pid *pid;struct task_struct *p;int trace = 0;long nr;.../*进程/线程的创建、分配资源的处理,主要由以下copy_process体现*/p = copy_process(clone_flags, stack_start, stack_size,child_tidptr, NULL, trace, tls, NUMA_NO_NODE);...if (IS_ERR(p))return PTR_ERR(p);.../*确认PID: 取PID由当前命名空间决定,每层命名空间都对应一个PID。*/pid = get_task_pid(p, PIDTYPE_PID);nr = pid_vnr(pid);.../*把分配好的进程/线程添加到调度模块中队列,开始执行*/wake_up_new_task(p);...return nr;
}该函数处理流程,主要关注标识如何产生的过程,过程中涉及到的命名空间概念,当作只有一层pid信息即可。
因代码过多而简化,详细内容请看【kernel/fork.c】
static __latent_entropy struct task_struct *copy_process(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *child_tidptr,struct pid *pid,int trace,unsigned long tls,int node)
{【AAA\检查标志】/** Don't allow sharing the root directory with processes in a different* namespace*/if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))return ERR_PTR(-EINVAL);...【BBB\申请新进程/线程的对象】retval = -ENOMEM;p = dup_task_struct(current, node);if (!p)goto fork_out;...【CCC\检查资源限制】if (atomic_read(&p->real_cred->user->processes) >=task_rlimit(p, RLIMIT_NPROC)) {if (p->real_cred->user != INIT_USER &&!capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN))goto bad_fork_free;} ...【DDD\初始化新进程/线程的对象】delayacct_tsk_init(p); /* Must remain after dup_task_struct() */p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER | PF_IDLE);p->flags |= PF_FORKNOEXEC;INIT_LIST_HEAD(&p->children);INIT_LIST_HEAD(&p->sibling);rcu_copy_process(p);p->vfork_done = NULL;spin_lock_init(&p->alloc_lock);...【EEE\设置调度相关配置(状态、调度器、优先级、CPU选项等)】/* Perform scheduler related setup. Assign this task to a CPU. */retval = sched_fork(clone_flags, p);if (retval)goto bad_fork_cleanup_policy;...【FFF\设置复制/共享资源(semundo、files、fs、sighand、signal、mm、namespaces、io、thread_tls等)】/* copy all the process information */shm_init_task(p);retval = security_task_alloc(p, clone_flags);if (retval)goto bad_fork_cleanup_audit;retval = copy_semundo(clone_flags, p);if (retval)goto bad_fork_cleanup_security;retval = copy_files(clone_flags, p);if (retval)goto bad_fork_cleanup_semundo;retval = copy_fs(clone_flags, p);...【GGG\设置进程标识、关系等】/*针对于进程\线程分配每一层命名空间的pid信息*/pid = alloc_pid(p->nsproxy->pid_ns_for_children);if (IS_ERR(pid)) {retval = PTR_ERR(pid);goto bad_fork_cleanup_thread;}.../*这块能看到进程和线程的区别处理,注意哦:如下处理流程中都是围绕顶层命名空间的PID处理*//* ok, now we should be set up.. */p->pid = pid_nr(pid);             if (clone_flags & CLONE_THREAD) {/*线程处理*/p->exit_signal = -1;p->group_leader = current->group_leader;    /*获取当前进程中的组长对象信息*/p->tgid = current->tgid;                   /*获取当前进程中的组长pid*/} else {if (clone_flags & CLONE_PARENT)p->exit_signal = current->group_leader->exit_signal;/*继承父进程的退出信号*/elsep->exit_signal = (clone_flags & CSIGNAL); /*设置自身的退出信号*/p->group_leader = p;                     /*相关pid就是它自己本身了,因资源独立了,没有必要依附于父进程资源*/p->tgid = p->pid;}...if (likely(p->pid)) {ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace);init_task_pid(p, PIDTYPE_PID, pid);if (thread_group_leader(p)) { /*产生pid、pgid、sid, 注意:PIDTYPE_TGID自己本身*/init_task_pid(p, PIDTYPE_TGID, pid);init_task_pid(p, PIDTYPE_PGID, task_pgrp(current));init_task_pid(p, PIDTYPE_SID, task_session(current));.../*加入到init_task列表,以及父进程的子进程列表*/list_add_tail(&p->sibling, &p->real_parent->children);list_add_tail_rcu(&p->tasks, &init_task.tasks);...} else {/*统计进程下的线程数量*/current->signal->nr_threads++;.../*放到进程的线程列表*/list_add_tail_rcu(&p->thread_group,&p->group_leader->thread_group);list_add_tail_rcu(&p->thread_node,&p->signal->thread_head);}...}
}

—越简单,易接受。在折腾路上…

错宗复杂的进程标识PID相关推荐

  1. 分布式系统中的进程标识

    陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 昨天跟朋友聊天,谈到了分布式系统中如何为进程取标识符(process identifier),写篇博客简单 ...

  2. 构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...

    对分布式系统中的进程标识"一文的疑问 刚才看到陈硕先生的一篇blog:"分布式系统中的进程标识",地址:http://www.cnblogs.com/Solstice/a ...

  3. linux 终端报错 Out of memory: Kill process[PID] [process name] score问题分析

    转自:http://www.111cn.net/sys/CentOS/84755.htm 从Out of memory来看是内存超出了,后面的 Kill process[PID] [process n ...

  4. 进程调度实验_Linux应用编程之进程的PID与PPID

    关注.星标公众号,直达精彩内容 ID:嵌入式情报局 作者:情报小哥 1进程PID 首先介绍PID的相关知识,为后面介绍fork函数进行铺垫. 01 PID与PPID  PID不是控制理论的PID算法, ...

  5. 安装完MySQL后启动报错_MySQL数据库之mysql编译安装完成后,启动时报错The server quit without updating PID file...

    本文主要向大家介绍了MySQL数据库之mysql编译安装完成后,启动时报错The server quit without updating PID file ,通过具体的内容向大家展现,希望对大家学习 ...

  6. linux命令获取进程pid_如何使用命令获取Linux进程的PID?

    PID或进程ID是标识进程的唯一编号.它们是由Linux内核在运行时创建的,进程调度程序控制着它们的CPU活动.因此,无论何时调用应用程序,内核都会首先产生必要的进程并为它们分配这些唯一的PID值.一 ...

  7. 进程,PID和PPID的区别

    目录 1.什么是进程? 2.如何查看进程 3.PID与PPID 1.什么是进程? 狭义定义:进程是正在运行的程序的实例(an instance of a computer program that i ...

  8. linux中每个进程都有唯一的进程标识,Linux进程标识

    1.进程标识 (1)进程标识说明 每个进程都有一个非负整型的唯一进程ID.因为进程ID标识符总是唯一的,常将其用作其他标识符的一部分以保证其唯一性. 在Linux中,进程ID 0是调度进程,常常被称为 ...

  9. Unix C学习笔记10 进程的概念,相关命令,父子孤尸,进程标识,创建子进程

    进程的概念 相关命令 pstree显示bash进程 ps显示进程,以快照方式,显示某一瞬间进程状态 ps aux top显示实时进程信息,会动态变化 父子孤尸 进程标识 会重用,但不会立马重用PID ...

最新文章

  1. 0基础JavaScript入门教程(一)认识代码
  2. python3安装常见问题_Python3下安装spyder及常见问题解决
  3. Flutter学习之Dart语法特性
  4. 滑动窗口—满足XX条件的最长子串
  5. java 对话框 显示图片_Java对话框上显示图片
  6. Sql server 2005 中的dense_rank()函数的应用
  7. 【系统架构设计师】软考高级职称,一次通过,倾尽所有,2016年下半年系统架构设计师考试论文真题(论述软件设计模式技术及应用)
  8. PAT 乙级 1042. 字符统计(20) Java版
  9. codeforces 340E Iahub and Permutations(错排or容斥)
  10. JetS3t使用说明
  11. C/C++程序之根据有向图、无向图求通路、回路、可达矩阵
  12. java影院订票系统图形界面,java简单影院订票系统Word版
  13. 交叉报表制作--Smartbi报表工具一步完成
  14. 租车小程序开发的必备功能
  15. 生日悖论与Hash函数的攻击
  16. python长度单位转化_长度单位的换算教学反思
  17. python求梯形面积_pythonocc 求一条直线与一个梯形的交点的横坐标
  18. 13 Msql之四种事务隔离界别
  19. 12306火车订票系统谈网站架构优化
  20. Stratifyd:全民化的人工智能如何助力增强社会责任感

热门文章

  1. 微信小程序发布时需要校验违法违规内容、图片,Java后端接口
  2. 动态的渐变色网页背景
  3. 『英语杂谈』 [好文共赏]Heal the World(转载)
  4. LIO-SAM imageProjection
  5. Unity 中实现UI左右滑动效果
  6. NOIp系列题目及CF小结
  7. Unity Hub那些事
  8. CF 1324-F Maximum White Subtree //树形换根dp
  9. 微信小程序开发--组织通讯录
  10. 卸载wps后office图标丢失变白,系统卡顿