写一个操作系统_11 Linux是怎么实现线程的

Linux2.6以前的线程

在Linux内核2.6出现之前进程是(最小)可调度的对象,当时的Linux不真正支持线程。Linux 2.4内核中不知道什么是“线程”,只有一个“task_struct”的数据结构,就是进程。

Linux内核有一个系统调用指令clone(),这个指令产生一个调用调用的进程的复件,而且这个复件与原进程使用同一地址空间。LinuxThreads计划使用这个系统调用来提供一个内核级的线程支持。但是这个解决方法与真正的POSIX标准有一些不兼容的地方,尤其是在信号处理、进程调度和进程间同步原语方面。

Native POSIX Thread Library

一个操作系统比较全面的支持线程是需要改内核的,怎么干改内核这个艰苦卓越的工作?Linux是开源、免费的,谁愿意来干这个活?

有两家公司参与了对LinuxThreads的改进(向他们致敬):IBM启动的NGTP(Next Generation POSIX Threads)项目,以及红帽Redhat公司的NPTL(Native POSIX Thread Library),IBM那个项目,在2003年因为种种原因放弃了,大家都转到NPTL这个项目来了。

因为Linux一开始就决定在进程的结构上支持线程,线程和进程都共用task_struct这个结构,所以这个设计一直延续了下来。所以说Linux下通过NPTL创建的线程是内核线程,他会在内核创建一个线程结构供处理器调度,也就是所谓的1:1模型。

用户级线程

举个例子,在收发网络包的时候,recv可以是阻塞的,这个时候如果没有网络回包,正在运行的进程会阻塞,然后这个正在运行的pthread 会从CPU上下来,调度其他的线程。

由于上面的问题,我们希望我们的程序不因为IO而终止运行,于是产生了用户级线程,我们在用户程序部分定义自己的线程(执行流),在线程阻塞之前主动切换。

对Linux来说,用户级的线程其实还是跑在pthread上面的,其中有两种模型比较出名:
M:1 : M个用户级线程跑在1个内核线程上,俗称 协程
M:N : M个用户级线程跑在N个内核级线程上,golang和baidu-rpc的做法

当然,这部分不是Linux做的,用户程序可以在内核线程的支持下实现

参考资料

-->