多线程 模型

有关多线程实现的疑问, 暂时想通一部分, 以此为记。  (网上很多资料ms矛盾, 这里仅取最*可能*的)

LWP: 轻量级线程,建立在内核上并由内核支持的用户线程。它由clone()系统调用创建,参数是CLONE_VM(即与父进程共享地址空间和系统资源)。每一个LWP均与内核线程关联,由内核管理并像普通进程一样调度。

根据管理线程(即调度者)是在用户态和内核态分为内核级线程和用户级线程,前者更利于并发使用多处理器的资源,而后者则更多考虑的是上下文切换开销。

内核级线程特点:因为线程切换时需要频繁的进出内核态,故效率低;另外需要占用内核的资源,线程数量有限制。(Linux不支持,Win NT支持,saloris 支持)。NT将所有的线程统一放进队列调度(不管是否是同一个进程的),用户线程和调度线程位于同一地址区间,线程切换时无需改动页表,大大降低了系统调用的开销,所以效率还可以。

用户级线程:因为切换时无需进入内核态(参setjmp.h)故效率高; 缺点是一个线程受阻时,所有该进程所有线程均受阻;同时单个进程的所有线程共享一个CPU,不能利用多CPU的优势)。
用户级线程有两种实现形式:
1.运行时系统:完全由线程库函数实现。 线程运行库(run-time)在用户线程每次进程系统调用的时候获取控制权,然后再决定是转发系统调用还是进行用户线程调度(需要改写原有的系统调用的用户库,插入用来和线程运行库交互的代码。这些插入的代码被称为外套-jacket或是封装器-wrapper)。如果线程很少系统调用,运行库很少有机会运行,只能等用户线程主动退出。
2. LWP  Linux线程使用clone函数创建参数为(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND)表示共享内存、共享文件系统访问计数、共享文件描述符表,以及共享信号处理方式。

 

背景知识:

针对线程模型的两大意义(并发使用多处理器和减少上下文切换开销),线程模型按照调度者在核内还是在核外分为核心级线程和用户级线程两种。目前的商用系统通常将两者结合起来使用,既提供核心线程以满足smp系统的需要,也支持用线程库的方式在用户态实现另一套线程机制,此时一个核心线程同时成为多个用户态线程的调度者。“混合”通常意味着更高的效率,但同时也意味着更大的实现难度。出于“简单”的设计思路,Linux从一开始就没有实现混合模型,它在实现上采用了另一种思路--LWP。

 

线程机制的实现,可以在操作系统内核,也可以在核外。后者要求核内实现进程(前者一般也要求核内支持进程)。内核级线程模型显然要求内核支持线程,而用户级线程模型则不一定基于后者实现(即用户级线程不一定基于核外线程来实现--比如,linux的用户级线程采用LWP实现,不是核外的线程)。当核内既支持进程也支持线程时,就可以实现线程-进程的“多对多”模型,即一个进程的某个线程由内核调度,而同时它也可以作为用户级线程池的调度者,选择合适的用户级线程在其空间中运行--这就是“混合”模型。大多数商业操作系统(如Digital Unix、Solaris、Irix)采用这种完全实现POSIX1003.1c标准的线程模型。

核外实现的线程可以分为“一对一”、“多对一”两种模型,前者用一个核心进程(或轻量进程-注:这里的核心进程只是说内核知晓进程/线程的存在,并不是内核线程kthread)对应一个线程,将线程调度等同于进程调度,交给核心完成;而后者则完全在核外实现多线程,调度也在用户态完成。后者即单纯的用户级线程模型,这种核外的线程调度只需完成线程栈的切换,开销非常小;但因为信号(无论是同步的还是异步的)是以进程为单位的,无法定位到线程,所以不能用于多处理器系统,也是因为如此,纯用户级线程的实现,除用于算法研究目的以外,几乎已经消失了。

Linux内核只支持LWP,限制了更高效的线程模型(内核级线程),但Linux着重优化了进程的调度开销,一定程度上弥补了这一缺陷。目前Linux最流行的LinuxThreads即Pthread采用“一对一”,将调度交给OS核心,而在用户级实现一个包括信号处理在内的线程管理机制。

 

LinuxThreads存在的问题:

1. 因为基于LWP而非核外线程实现,故同一进程的所有线程的PID不同。 (2.6下的新版本同一进程内的线程返回的pid是一样。代码如下:)

get_pid()
if (flags & CLONE_PID)
return current->pid;

 

2. 同样,因为LWP对于内核来说就是一个进程,同时也没有线程组的概念,无法向进程中所有线程发送信号。LinuxThreads只能将一个线程挂起,而无法挂起整个进程。

3. 线程的总数有限制。

4. 线程管理瓶颈。一旦管理线程死了,后续的用户线程需要用户手工清理;同时也不能处理后续的创建线程请求。

5. 同步问题。因为线程间通信采用信号的方式,效率一直是个问题。

6. POSIX兼容问题。很多系统调用仅仅适用于单个线程,而非进程下的所有线程。

7. 实时性问题。不仅pthread,即时linux没有做太多。

2.6内核下的NPTL,继续适用1:1模型,同时不再适用管理线程,将线程的管理直接放在核内,优化了性能,缺点是仍没有100%POSIX兼容。

 

 affinity: 线程的资源亲和性,主要是指CPU的亲和性。

int pthread_attr_setscope(pthread_attr_t*attr,intscope);

POSIX.1-2001 specifies two possible values forscope: PTHREAD_SCOPE_SYSTEM 和PTHREAD_SCOPE_PROCESS。POSIX.1-2001 only requires that an implementation support one of these contention scopes, but permits both to be supported. Linux supportsPTHREAD_SCOPE_SYSTEM, but notPTHREAD_SCOPE_PROCESS.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值