作者:大河
链接:https://www.zhihu.com/question/35128513/answer/148038406
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原问题:Linux下调用pthread库创建的线程是属于用户级线程还是内核级线程?求大神指教?

这个事情,还真不是一句话就能回答的,因为涉及到Linux和编译器的版本关于线程的概念不多说了,内核级和用户级线程的定义网上也有,简单的说:内核级就是操作系统内核支持,用户级就是函数库实现(也就是说,不管你操作系统是不是支持线程的,我都可以在你上面用多线程编程)。

好了,那么,我们首先明白一件事:不管 Linux 还是什么 OS,都可以多线程编程的,怎么多线程编程呢?程序员要创建一个线程,当然需要使用 xxx 函数,这个函数如果是操作系统本身就提供的系统函数,当然没问题,操作系统创建的线程,自然是内核级的了。如果操作系统没有提供“创建线程”的函数(比如Linux 2.4及以前的版本,因为 Linux 刚诞生那时候,还没有“线程”的概念,能处理多“进程”就不错了),当然你程序员也没办法在操作系统上创建线程。所以,Linux 2.4 内核中不知道什么是“线程”,只有一个“task_struct”的数据结构,就是进程。

那么,后来随着科学技术的发展,大家提出线程的概念,而且,线程有时候的确是个好东西,于是,我们希望 Linux 能加入“多线程”编程。要修改一个操作系统,那是很复杂的事情,特别是当操作系统越来越庞大的时候。怎么才能让Linux支持“多线程”呢?首先,最简单的,就是不去动操作系统的“内核”,而是写一个函数库来“模拟”线程。也就是说,我用 C 写一个函数,比如 create_thread,这个函数最终在 Linux 的内核里还是去调用了创建“进程”的函数去创建了一个进程(因为 OS 没变嘛,没有线程这个东西)。 如果有人要多线程编程,那么你就调用 这个 create_thread 去创建线程吧,好了,这个线程,就是用库函数创建的线程,就是所谓的“用户级线程”了。

等等,这是神马意思?赤裸裸的欺骗?也不是。为什么不是?因为别人给你提供了这个线程函数,你创建了“线程”,那么,你的线程(虽然本质上还是进程)就有了“线程”的一些“特征”,比如可以共享变量啊什么的,咦?那怎么做到的?当然有一套机制,反正人家给你做好了,你用就行了。这种欺骗自然是不“完美”的,有线程的“一些”特征,但不能完全符合理论上的“线程”的概念(POSIX的要求),比如,这种多线程不能被分配到多核上,用户创建的N个线程,对于着内核里面其实就一个“进程”,导致调度啊,管理啊麻烦…..为什么要采用这种“模拟”的方式呢?改内核不是一天两天的事情,先将就用着吧。内核慢慢来改。

怎么干改内核这个艰苦卓越的工作?Linux 是开源、免费的,谁愿意来干这个活?有两家公司参与了对 LinuxThreads 的改进(向他们致敬):IBM 启动的NGTP(Next Generation POSIX Threads)项目,以及红帽 Redhat 公司的NPTL(Native POSIX Thread Library),IBM那个项目,在 2003 年因为种种原因放弃了,大家都转到NPTL这个项目来了。最终,当然是成功了。

在Linux 2.6的内核版本中,这个 NPTL 项目怎么做的呢?并不是在 Linux 内核中加了一个“线程”,仍然和原来一样,进程(其实,进程线程就是个概念,对于计算机,只要能高效的实现这个概念就行,程序员能用就 OK,管它究竟怎么实现的),不过,用的 clone 实现的轻量级进程,内核又增加了若干机制来保证线程的表现和 POSIX 相同,最关键的一点,用户调用 pthread 库创建的一个线程,会在内核创建一个“线程”,这就是所谓的 1:1 模型。所以,Linux 下,是有“内核级”线程的,网上很多说 Linux 是用户级线程,都是不完整的,说的Linux很早以前的版本(现在 Linux 已经是 4.X 的版本了)。

还有个 pthread 的问题,pthread是个线程函数库,他提供了一些函数,让程序员可以用它来创建,使用线程。那么问题是,这个函数库里面的函数,比如 pthread_create 创建线程的函数,他是怎么实现的呢?他如果是用以前的方法,那程序员用它来创建的线程,还是“用户级”线程;如果它使用了NPTL方式创建线程,那么,它创建的线程,就是“内核级”线程。

OK,结论,如果你 (1) 使用2.6的内核的系统平台,(2) 你的gcc支持 NPTL (现在一般都支持),那么你编译出来的多线程程序,就是“内核级”线程了。

所以,现在回答问题,只要你不是很古董级的电脑,Linux下用 pthread 创建的线程是“内核级线程”最后,这 NPTL 也并不是完美的,还有一些小问题,像有一些商业操作系统,可以实现混合模型,如 1:1,N:M等(就是内核线程和用户线程的对应关系),这就强大了,Linux仍有改进的空间。

Logo

更多推荐