在LINUX内核中,进程标识符PID为1,2 ,3,4,5的进程的名称是啥?基本功能是啥?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在LINUX内核中,进程标识符PID为1,2 ,3,4,5的进程的名称是啥?基本功能是啥?相关的知识,希望对你有一定的参考价值。

pid=1 :init进程,系统启动的第一个用户级进程,是所有其它进程的父进程,引导用户空间服务。

pid=2 :kthreadd:用于内核线程管理。
pid=3 :migration,用于进程在不同的CPU间迁移。
pid=4 :ksoftirqd,内核里的软中断守护线程,用于在系统空闲时定时处理软中断事务。
pid=5 :watchdog,此进程是看门狗进程,用于监听内核异常。当系统出现宕机,可以利用watchdog进程将宕机时的一些堆栈信息写入指定文件,用于事后分析宕机的原因。
参考技术A pid为 1 的一定是init进程.
它是内核运行后的第一个进程. 它的作用你可以在网上查一下.
总的来说功能很多.包括 runlevel, 驱动, 启动服务啥地都会做,感觉事情很多.

2-5 这些进程在不同的内核中往往名字也不太一样. 用 ps ax列出时进程名也带有中括号. 这些都是内核的一些进程作用详不清楚 .如果愿意可以在网上查一下.

Linux 上的线程标识

Linux 上的线程标识

进程PID、线程PID、线程TID

进程PID:进程开启之后,在系统中是唯一的,不可重复的

线程TID:创建一个线程之后,线程有一个标识符,此标识符只在该线程所属的进程上下文才有意义,为pthread_t数据类型。在不同的进程中,可能会出现相同的情况

线程PID:Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。在系统中是唯一的,不可重复的

PS : 主线程PID等于线程所在的进程的PID

线程TID (pthread_t)

  • 进程ID是存在于整个系统中的,但线程ID不同,线程ID只有在它所属的进程上下文中才有意义
  • 重点:因为线程ID只在所属的进程上下文才有意义,所以不同的进程创建的不同线程可能具有相同的线程ID
  • TID的类型是: pthread_t,是一个结构体数据类型,所以可移植操作系统实现不能把它作为整数处理

POSIX threads库提供了 pthread_self 函数用于返回当前进程的标识符,其类型为pthread_t

pthread_t 不一定是一个数值类型(整数或指针),也有可能是一个结构体,因此Pthreads专门提供了 pthread_equal 函数用于对比两个线程标识符是否相等

这就带来一系列问题,包括:

  • 无法打印输出 pthread_t ,因为不知道其确切类型。也就没法在日志中用它表示当前线程的id
  • 无法比较 pthread_t 的大小或计算其hash值,因此无法用作关联容器的key
  • 无法定义一个非法的 pthread_t 值,用来表示绝对不可能存在的线程id,因此MutexLock class没有办法有效判断当前线程是否已经持有锁
  • pthread_t 值只在进程内有意义,与操作系统的任务调度之间无法建立有效关联。比方说在/proc文件系统中找不到 pthread_t 对应的task

另外,glibc的Pthreads实现实际上把 pthread_t 用作一个结构体指针 (它的类型是unsigned long),指向一块动态分配的内存,而且这块内存是反复使用的。这就造成 pthread_t 的值很容易重复。Pthreads只保证同一进程之内,同一时刻的各个线程的id不同;不能保证同一进程先后多个线程具有不同的id,更不要说一台机器上多个进程之间的id唯一性了。

例如,下面这段代码中先后两个线程的标识符是相同的:

#include <stdio.h>
#include <pthread.h>
 
void *threadFunc(void*){}
 
int main()
{
    pthread_t t1,t2;
    
    pthread_create(&t1,NULL,threadFunc,NULL); //创建线程
    printf("%lx\\n",t1);                       //打印线程id
    pthread_join(t1,NULL);                    //阻塞等待t1线程结束
 
    pthread_create(&t2,NULL,threadFunc,NULL);
    printf("%lx\\n",t2);
    pthread_join(t2,NULL);
    
    return 0;
}

因此,pthread_t并不适合用作程序中对线程的标识符

线程的PID (pid_t)

在Linux上,建议使用gettid系统调用的返回值作为线程id
这么做的好处有:

  • 它的类型是pid_t,其值通常是一个小整数(最大值是/proc/sys/kernel/pid_max,默认值是32768),便于在日志中输出
  • 在现代Linux中,它直接表示内核的任务调度id,因此在/proc文件系统中可以轻易找到对应项:/proc/tid或/prod/pid/task/tid
  • 在其他系统工具中也容易定位到具体某一个线程,例如在top中我们可以按线程列出任务,然后找出CPU使用率最高的线程id,再根据程序日志判断到底哪一个线程在耗用CPU
  • 任何时刻都是全局唯一的,并且由于Linux分配新pid采用递增轮回办法,短时间内启动的多个线程也会具有不同的线程id
  • 0是非法值,因为操作系统第一个进程init的pid是1

但是glibc并没有封装这个系统调用,需要我们自己实现。封装gettid很简单,但是每次都执行一次系统调用似乎有些浪费,如何才 能做到更高效呢?

  • __thread 变量来缓存gettid的返回值,这样只有在本线程第一次调用的时候才进行系统调用,以后都是直接从 thread local 缓存的线程id拿到结果(这个做法是受了glibc封装getpid()的启发),效率无忧
  • 多线程程序在打日志的时候可以在每一条日志消息中包含当前线程的id,不必担心有效率损失。读者有兴趣的话可以对比一下boost::this_thread::get_id()的实现效率

还有一个小问题,万一程序执行了fork,,那么子进程会不会看到stale的缓存结果呢?解决办法是用 pthread_atfork() 注册一个回调,用于清空缓存的线程id。

以上是关于在LINUX内核中,进程标识符PID为1,2 ,3,4,5的进程的名称是啥?基本功能是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Linux内核分析——进程的描述和进程的创建

Linux内核是如何创建一个新进程的?

《Linux内核与分析》第六周

Linux进程管理

Linux内核接口特定的类型

linux下变成——操作系统——信号