2.2线程

2.2.1 线程的使用

  对于线程的理解,我认为是在操作系统对于进程的分工上与之对应的进程对于线程的分工,本质上都是分工。

  为什么需要线程?在许多应用中同时发生着许多活动,将这些活动分解成单个模块会给程序设计带来巨大的便利,不止体现在效率与分工上。比如web服务器,一个称为分派程序(dispatcher)的线程负责处理网络请求,它挑选一个空转的(dallying)即非阻塞的工作线程来处理这个请求。如图:

2.2.2 经典的线程模型

  进程可以有多个线程,每个线程共享着进程的虚拟地址空间,然而每个线程有自己的堆栈与程序计数器,状态等,用于线程的切换上下文(context),和传统进程一样,线程也有四个状态:运行(正在占用cpu),阻塞(空转),就绪,终止。和进程之间的父子关系不一样的是,线程之间的关系是平等的。一个常见的进程调用是thread_yield,允许调用线程放弃自己占用cpu的资源让给另一个线程,还有几个是thread_create,thread_exit,thread_join。相关如图:

      

2.2.3 POSIX线程

  IEEE在标准10031c中定义了线程的标准,组织定义的线程包称为pthread,一般的unix系统都支持该标准,该标准定义 超过60个函数调用,下面介绍几个基本的调用:

  1.pthread_create  创建一个新的线程

  2.pthread_exit    结束调用的线程

  3.pthread_join      等待一个特定线程退出

  4.pthread_yield     释放cpu来运行另外一个线程

  5.pthread_attr_init   创建并初始化一个线程的属性结构

  6.pthread_attr_destory 删除一个线程的属性结构

ps:线程的属性结构是指其保留的堆栈,程序计数器等。而退出只是指暂时放弃cpu资源。

2.2.4 在用户空间中实现线程  

  在用户空间中实现线程:优点是线程之间的切换很快,可以在纳秒级完成切换。进程有一个线程表,记录每个线程的程序计数器,堆栈等,允许进程有自己的调度算法,比如说c#WPF框架中的前台线程和后台线程。然而也有一些缺点:因为内核将用户空间的进程看做为单线程,所以当一个线程请求一个阻塞系统调用的时候,进程只能阻塞所有的进程;另外一个问题就是在进程内部,如果一个线程开始执行,那么其他线程就不能执行,除非该运行线程自动放弃cpu,这也导致了因为依靠时钟中断的轮转调度算法没法自动地使线程切换。如图:

  

  在内核中支持线程:内核管理着线程表,缺点就是创建或撤销线程的代价较大。

  混合实现:一种方式是使用内核级线程,同时将用户线程与某些或者全部内核线程多路复用起来,这就综合了以上两者的优点,带来了巨大的灵活度。如图:

2.2.7 调度程序激活机制

  当内核了解到一个线程被阻塞之后,内核通知该进程的运行时系统,并且在堆栈中以参数形式传递有问题的线程编号和所发生事件的一一个描述。内核通过在一个已知的起始地址启动运行时系统,从而发出了通知。这个机制称为上行调用(upcall)。其实我对这个不是很懂。。。

2.2.8 弹出式线程

  在分布式系统中经常使用线程,一个问题是如何处理到来的消息,传统方法是将线程阻塞在一个receive的系统调用上,等待消息的到来,并处理。另一个方法就是一个消息的到来将使进程创建一个线程来处理这个消息,称为弹出式线程。如图:

  

2.2.9 使单线程代码多线程化

猜你喜欢

转载自www.cnblogs.com/manch1n/p/10299473.html