一 ”模型(One-to-One), 它可以利用多处理器。该库基于LINUX的一个新的系统
调用--clone()(也就是说它只能用在LINUX上了)。该调用实现于LINUX2.0或以
上版本,并可以运行于Intel,Alpha SPARC,m68k以及MIPS等处理器的机器上。其
一个缺点在于它对信号的非标准处理上。
LinuxThreads采用称为1-1模型:每个线程实际上在核心是一个个单独的进程,核心
的调度程序负责线程的调度,就象调度普通进程。线程是用系统调用clone()创建的
,clone()系统调用是fork()的推广形式,它允许新进程共享父进程的存储空间、文
件描述符和信号处理程序。
“一对一”模型的优点在于:
A 最小限度消耗的CPU级多处理技术(每个CPU一个线程);
B 最小限度消耗的I/O操作;
C 一种简单和强壮的实现(核心调度程序为我们做了大部分艰难的工作)。
该模型主要的缺点在于在互斥和条件操作时的环境切换的系统消耗更大,而该切换
是通过内核来进行的。但是由于LINUX内核对环境切换的处理相当有效,因此在一定
程度上弥补了这个缺点。
除了“一对一”模型之外还有两种基本模型。
“多对一”模型基于用户级的调度,线程切换完全由用户程序完成;从核心角度看,
只有一个进程正在运行。这种模型不是我们所关心的,因为它无法利用多处理器的
优点,而且要用不合理的方法处理I/O操作阻塞。目前LINUX上存在有数个用户态的
线程库,但我发现它们在功能、性能以及强壮性上都存在缺陷。
“多对多”模型结合了核心态和用户态的调度:数个核心态线程并发的执行,每个
都作为一个用户态线程的调度者对用户态线程进行调度。大多数商业版本的UNIX(
SOLARIS,DIGITAL UNIX和IRIX)都采用此模型实现POSIX线程标准。该模型结合了
“多对一”和“一对一”模型的优点,而且由于它能够避免另外两种模型缺陷,尤
其是当内核在处理环境切换时效率较低时,比如DIGITAL UNIX,因而相当具有吸引
力。但不幸的是,这种模型的实现相当复杂,而且需要LINUX内核所不能提供的内核
功能。Linus Torvalds和其它Linux内核开发者一直以来都在全面简单化的原则下推
动“一对一”模型,并且他们大大的提高了Linux内核线程切换的效率。Linux线程遵
从了他们一直以来的原则。
2 Linux核心对线程的支持
Linux核心对线程的支持主要是通过其系统调用,下文将进行系统的介绍。
2.1 系统调用clone()
以下是系统调用clone的代码:
asmlinkage int sys_clone(struct pt_regs regs)
{
unsigned long clone_flags;
unsigned long newsp;
clone_flags = regs.ebx;
newsp = regs.ecx;
if (!newsp)
newsp = regs.esp;
return do_fork(clone_flags, newsp, ®s);
}
与系统调用clone功能相似的系统调用有fork,但fork事实上只是clone的功能的一部
分,clone与fork的主要区别在于传递了几个参数,而当中最重要的参数就是
conle_flags,下表是系统定义的几个clone_flags标志:
标志 Value 含义
CLONE_VM 0x00000100 置起此标志在进程间共享地址空间
CLONE_FS 0x00000200 置起此标志在进程间共享文件系统信息
CLONE_FILES 0x00000400 置起此标志在进程间共享打开的文件
CLONE_SIGHAND 0x00000800 置起此标志在进程间共享信号处理程序
如果置起以上标志所做的处理分别是:
置起CLONE_VM标志:
mmget(current->mm);
/*
* Set up the LDT descriptor for the clone task.
*/
copy_segments(nr, tsk, NULL);
SET_PAGE_DIR(tsk, current->mm->pgd);
置起CLONE_ FS标志:
atomic_inc(¤t->fs->count);
置起CLONE_ FILES标志:
atomic_inc(&oldf->count);
置起CLONE_ SIGHAND标志:
atomic_inc(¤t->sig->count);
2.2 与线程调度相关的系统调用
以下是glibc-linuxthread用来进行调度的系统调度:
.long SYMBOL_NAME(sys_sched_setparam) /* 系统调用154 */
/*用来设置进程(或线程)的调度参数*/
.long SYMBOL_NAME(sys_sched_getparam)
/*用来获取进程(或线程)的调度参数*/
.long SYMBOL_NAME(sys_sched_setscheduler)
/*用来设置进程(或线程)的调度参数*/
.long SYMBOL_NAME(sys_sched_getscheduler)
/*用来获取进程(或线程)的调度参数*/