1、在用户空间中实现线程
(1)特点:把整个线程包放在用户空间,内核对线程包一无所知。从内核角度考虑,就是按正常的方式管理,即单线程进程(存在运行时系统)
(2)优点:
1、用户级线程包可以在不支持线程的操作系统上实现。
2、线程切换至少要比陷入内核要快一个数量级。在线程完成运行时,它调用thread_yield可以把该线程的信息保存在线程表中;进而,它可以调用线程调度程序来选择另一个要运行的线程。保存该线程状态的过程和调度程序都只是本地过程,所以启动它们比进行内核调用效率更高。另一方面,不需要陷阱,不需要上下文切换,也不需要对内存高速缓存进行刷新,这使得线程调度非常快捷。
在用户空间管理线程时,每个进程都需要有其专用的线程表,用来跟踪该进程中的线程。与进程表类似,线程表记录各个线程的属性,如每个线程的程序计数器,堆栈指针,寄存器和状态等,线程表由运行时系统管理,当一个线程转换到就绪状态或阻塞状态是,在该线程表中存放重新启动该线程所需的信息,与内核在进程表中存放进程的信息完全一样。
当某个线程做了一些会引起在本地阻塞的事情之后,例如等待进程中另一个线程完成某些工作,它调用一个运行时系统的过程,这个过程检查该线程是否必须进入阻塞状态。如果是,它在线程表中保持该线程的寄存器,并查看表中可运行的就绪线程,并把新线程的保存值重新装入机器的寄存器中。只要堆栈指针和程序计数器一被切换,新线程就又自动投入运行。
(3) 允许每个进程有自己定制的调度算法。
(4) 具有较好的可扩展性,这是因为在内核空间中内核线程需要一些固定表格空间和堆栈空间,当内核线程的数量非常大,就会出现问题。
(3)缺点:
线程发生I/O或页面故障引起的阻塞时,如果调用阻塞系统调用则内核由于不知道有多线程的存在,而会阻塞整个进程从而阻塞所有线程。注(阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。)
在一个单独的进程内部,没有时钟中断,所以不能用轮转调度的方式调度线程。如果一个线程开始运行,那么在该进程中的其他线程就不能运行,除非第一个线程自动放弃CPU。
下面是线程包实现图
2、在内核中实现线程
(1)特点:
在内核中实现线程,此时不再需要运行时系统。另外,每个进程中也没有线程表,相反,在内核中用来记录系统中所有线程的线程表。当一个线程阻塞时,内核可以根据其选择,可以运行同一个进程中的另一个线程,或者运行另一个进程中的线程。而在用户级线程中,运行时系统始终运行自己进程中的线程,直到内核剥夺它的CPU为止。当某个线程希望创建一个新线程或撤销一个已有线程时,它进行一个系统调用。在内核中实现线程时,内核必须维护两个表,传统的进程表以便跟踪进程的状态和线程表。
(2)优点:
内核线程不需要任何新的,非阻塞系统调用。另外,如果某个进程中的线程引起了页面故障,内核可以很方便地检查该进程是否有任何其他可运行的线程,如果有,在等待所需要的页面从磁盘读入时,就选择一个可运行的线程运行。
(3)内核级线程的缺点是:应用程序线程在用户态运行,而线程调度和管理在内核实现。在同一进程中,控制权从一个线程转移到另一个线程,需要用户态-内核态-用户态的模式切换,系统开销较大。(应用程序线程和线程调度管理,都在同一进程内)
综上:用户级线程和内核级线程之间的差别在于性能。用户级线程的切换需要少量的机器指令,而内核级线程需要完整的上下文切换,修改内存映像,使高速缓存失效,这导致了若干数量级的延迟。另一方面,在使用内核级线程时,一旦线程阻塞在I/O就不需要像在用户级线程中那样将整个进程挂起。
所有能够阻塞线程的调用都以系统调用的形式实现,代价可观。当一个线程阻塞时,内核根据选择可以运行另一个进程的线程,而用户空间实现的线程中,运行时系统始终运行自己进程中的线程。说明:由于内核创建线程代价大,故有线程回收。
线程调度
当若干进程都有多个线程时,存在两个层次的并行,进程和线程。这样的系统中调度处理有本质的区别,是用户级线程还是内核级线程。
对于用户级线程,内核并不知道有线程存在,所以内核还是和以前一样地操作,选取一个进程,假设为A,并给予A时间片控制,A的线程调度程序决定哪个线程运行,假设为A1。由于多道线程不存在时钟中断,所以,这个线程可以按其意愿任意运行多长时间。如果该线程用完了进程的全部时间片,内核就会选择另一个进程运行。
在线程A终于又一次运行时,线程A1会接着运行。该线程会继续耗费A进程的所有时间,直到它完成工作。不过,该线程的这种不合群的行为不会影响到其他的进程。其他进程会得到调度程序所分配的合适份额,不会考虑进程A内部所发生的事。但是,用户级线程缺乏一个时钟将运行过长的线程加以中断。
对于内核级线程而言,内核选择一个特定的线程运行,它不用考虑该线程属于哪个进程,不过,如果有必要的话,它可以这样做。对被选择的线程赋予一个时间片,而且,如果超过了时间片,就会强制挂起该线程。