thread deep dive
0. 调度器
- 调度器,调度的是task or in fact kernel thread.
- kernel version < 2.4 : O(n)调度器 调度的时间复杂度与进程数目n相关--> 1个全局链表管理进程,需要遍历/锁链表计算动态/静态优先级.
- kernel version >= 2.6 : O(1)调度器 单链表 --> 多个优先级链表;使用了很多hardcode的常数
调度器介绍 - from wowotech - CFS调度器...
0.1. process/thread的几个概念
- 进程:
- 进程描述符:
task struct
,其中包含一个mm_struct为该进程的虚拟内存空间. - rt进程, 实时进程
- nice, 进程静态优先级,越小优先级越高 --> 与调度器相关,调度时根据nice值调整分配时间片大小. 进程动态优先级与当前该进程已经跑了几个滴答(tick)相关.
- cpu affinity, cpu亲和力,该进程上一次时间片在某个core中跑的.由于把该进程调度到该core,l1缓存命中率会较高,cpu亲和力就是衡量该属性的指标.(l1 cache 是每个core独有的,其他l的cache可能会被core共享)
- 进程描述符:
- 线程:
- kernel thread的
mm_struct
为NULL
- userspace thread的实现则与平台相关.
- userspace thread 与 kernel thread 根据不同实现有不同的对应关系,如
1:1
,m:n
.
- kernel thread的
- 进程与线程的区别:
- 程序概念上,进程是资源分配(如虚拟内存空间)的单位,线程是cpu调度的单位.
- 更进一步的区别:1:1模型下的线程与进程
1. Userspace Thread的实现: LinuxThread vs. NPTL
Linux上线程的实现主要有2种,LinuxThread(旧版本)和Redhat的NPTL(Native POSIX Thread Library),2者都分别实现了POSIX Thread标准.
不同平台的pthread引的实现不同.
-
LinuxThread
- 内核版本 2.0;
- 使用的系统调用是clone();
- 存在的问题:
- 每次新建线程都需
clone full process
并且需要一个所谓manager thread
管理; - 资源监控容易令人费解,不区分process和thread,如内存消耗等指示无法确认属于某进程的线程使用多少内存,每个线程的内存占用都是该进程的;
- 线程的信号处理存在一些问题.
Because each thread had its own process ID, asynchronous signals could only be sent to a particular thread, not to the process as a whole.
- 例如,用户
ctrl+z
一个进程,只能停止某个特定线程,如果该进程有其他工作线程,将无法停止.
- 例如,用户
- getpid()不符合POSIX标准,同一个进程的不同线程将返回不同的pid号.
- 每次新建线程都需
- 被加入glibc,并从96年一直沿用到现在.
- 用户态线程与内核线程的关系:
1:1
.
-
NPTL
- 内核版本 2.5;
- 使用的系统调用有:clone(),futex()等;
- 用户态线程与内核线程的关系:
1:1
. - NPTL的基础是内核版本2.5中Molnar提交的一系列内核patch带来的新特性:
-
clone()
添加针对thread生成的优化.Using clone() to spawn a thread is no longer a heavyweight task.
- 支持
thread-specific data areas
- A new mechanism for tracking threads.
- 进程作为资源的分配单元,如信号,内存使用等.
- Fast Userspace Locking (futex)
- 进程内的线程之间的关系: a parent-child relationship ---> a true peer relationship.
- fix getpid()
-
-
为什么NPTL最后使用1:1的线程模型?
这里的1:1
是指用户线程与内核线程的比例.
NPTL白皮书的说法是:
主要从2个角度说明为何采用了1:1
-
m:n
模型应该如何实现,需要有1个用户态的调度器,以便把m个用户线程调度到n个内核线程上,由于内核本身
有任务调度器,如果该用户态调度器不与内核的任务调度器协同的话,性能会有严重影响(Cache Miss);
如果该用户态调度器与内核的任务调度器协同,又会带来一些额外开销. -
m:n
模型能带来什么,可以减少内核线程的数目. 由于2.6版本引入了O(1)调度器,这个减少内核线程
不会带来太多收益.
-
-
关于POSIX标准中的
PTHREAD_SCOPE_PROCESS
,linux是否不支持呢?- 在某个google group中找到了答案,如果单纯只有nptl,那么应该是不支持
process_scope
的,因为其线程模型是1:1
的,
所有用户线程一起竞争cpu,也就是system_scope
. - 但提到,可以通过
cgroup
实现process_scope
,做法是将某个process的所有thread绑定到一起.
- 在某个google group中找到了答案,如果单纯只有nptl,那么应该是不支持
-
practice
-
top -H
中的pid其实是tid
-
NPTL from drdobbs
NPTL white paper
pthread on linux with process_scope
使用pthread
- scope不用考虑了,因为linux只支持system_scope
- detached or not detached: 这个主要跟业务相关,看业务是否需要线程的退出状态。(大部分工作线程是不需要的,也就是大多数都是用non-detached,即使需要看线程工作退出状态,大多也是自己维护一个线程状态结构)
a simple abstraction of thread
可以参考seastar中对thread的封装.(他本身多了一个业务层面的调度器)
网友评论