统计
日志总数: 128
评论总数: 123
日志分类
日志归档
最近日志
最近评论
订阅
|
|
【编程】
|
阅读 7602 次
|
Linux 到现在还是没有线程呀??!
2012-08-18 11:13:59
Linux线程模型
Linux中的多线程编程可使用pthread库。它的用法相对简单,不过对于其内部的工作原理,相关的技术资料并不多见。本文将讨论Linux下的线程模型及其工作原理。
我们先从pthread库的应用示例开始。我们通常所用的pthread库是GNU的C库glibc的一部分,通常你可以在Linux的/lib目录找到名为libpthread-x.x.so(x.x是版本号)的库,这就是多线程编程时所需要的pthread库。pthread可看作是POSIX thread的简写,POSIX对线程定义了一系列的标准,而glibc的pthread库则是对POSIX线程标准的实现。
下面的代码示例了一个简单的多线程程序:
#include <pthread.h>
#include <stdio.h>
void* threadFunc(void* arg)
{
printf("I am running in sub thread.\n");
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, threadFunc, NULL);
pthread_join(tid, NULL);
printf("I am running in main thread.\n");
return 0;
} |
这个程序在链接时需要指定链接pthread库,否则将出现链接错误。这是因为pthread库相对标准C库libc.so来说,是一个单独的库,而libc则是默认被链接的。
下面的命令可顺利编译上面的代码,注意-l参数的使用,用来指定链接pthread库:
# gcc -o test thread.c –lpthread |
上面的代码非常简单,仅仅是示例了使用pthread_create()函数创建了一个线程,对pthread库中函数的用法本文不作详细解释,不熟悉的读者可用man命令阅读相关文档。
glibc的pthread库是glibc利用Linux内核提供的系统调用来实现的线程库,对于2.4和2.6的内核,由于对线程的支持有所不同,其实现效率也有所差别。简言之,采用2.4及之前的内核的Linux系统通常使用较老的LinuxThreads项目提供的线程模型(当然这并不绝对,采用2.4内核的Redhat较早的试用了NPTL),而采用2.6内核的系统则通常采用新的NPTL项目提供的线程模型,后者的效率比前者要高得多,也更符合POSIX标准。
在Linux的内核中,进程是进行调度的最小单位,并没有真正的对线程的支持,可以说线程只是用户空间的概念,在内核中只能用进程来实现线程。一个进程的多个线程在内核中只是多个特殊的进程,它们虽然有各自的进程描述结构,却共享同一个代码上下文。在Linux上,这样的进程称为轻量级进程(Light weight process)。
同时,Linux内核提供了clone()系统调用,用来创建进程的一个拷贝,这个拷贝与被拷贝的进程共享相同的地址空间。LinuxThreads 项目正是使用这个调用来完全在用户空间模拟对线程的支持。这个任务在当时内核支持不够的条件下,具体的实现非常复杂。由于内核并没有线程组的概念,LinuxThreads模型只能在pthread库中,对每个进程下的线程组都增加一个额外的线程来进行管理,这就是LinuxThreads模型中著名的管理线程(Manager Thread)。这个管理进程负责对管理同一进程下的其他线程的创建、退出,资源的分配和回收,及线程切换等,非常复杂,开销也很大,而且一旦管理线程被杀死,其他线程都不能正确回收。另外,由于当时内核中缺乏对线程同步操作的支持,因此pthread库中的互斥量mutex等只能采用信号来实现,效率非常低。LinuxThreads模型在某些方面也不符合POSIX标准,比如用它在同一进程中创建的线程,都有自己唯一的进程ID,而不是同一个ID,而且接收信号的时候也只能按线程接收。
正是由于LinuxThreads模型的这些问题,Redhat的一些开发人员发起了NPTL(Native POSIX Thread Library)项目,来改进pthread线程库的这些缺点。目前基于NPTL模型实现的pthread线程库已被多数2.6内核的Linux系统采用,你可以用下面的命令来查看所使用的线程模型是NPTL还是LinuxThreads:
# getconf GNU_LIBPTHREAD_VERSION |
如果得到的结果是类似于“NPTL 2.5”则是使用NPTL,如果是“linuxthreads-0.10”则是LinuxThreads。
NPTL模型仍然采用clone()系统调用,在内核中还是通过进程来模拟线程,不过对LinuxThreads的一些主要缺点有很大的改进:
• 在内核中改进了clone()系统调用并引入新的exit_group()系统调用,优化了线程创建和结束,并且使得pthread库中不再需要管理线程,减少了很多开销。
• 在内核中引入新的线程同步原语Futex,并基于Futex来实现线程同步操作如互斥量、条件变量等,改进了原来LinuxThreads基于信号实现时的低效率。
• 符合POSIX标准:发送信号时能发送到同一进程下的所有线程;getpid()会为同一进程下的所有线程返回相同的进程ID。
▲评论
|