2011年4月27日星期三

线程思考

先引一段别人的思考: http://www.cppblog.com/CppExplore/archive/2008/01/15/41175.html
一、线程使用场景。
使用线程的方式大致有两种:
(1)流水线方式。根据业务特点,将一个流程的处理分割成多个线程,形成流水线的处理方式。产生的结果:延长单一流程的处理时间,提高系统整体的吞吐能力。
(2)线程池方式。针对处理时间比较长且没有内蕴状态的线程,使用线程池方式分流消息,加快对线程消息的处理,避免其成为系统瓶颈。
线程使用的关键是 线程消息队列、线程锁、智能指针 的 使用。其中以线程消息队列最为重要。

二、线程消息队列描述。所谓线程消息队列,就是一个普通的循环队列(其它数据结构也未尝不可,具体内容请参考数据结构课本)加上“多生产者-单(多)消费者的PV操作”(详细内容请参考操作系统课本)。流水线方式中的线程是单消费者,线程池方式中的线程是多消费者。
为了后文更好的描述问题,作如下说明:
(1)假定循环队列CircleQueue中,存放的消息指针类型是MyMSG *,入队操作EnQueue,出队操作DeQueue,判断队满IsQueueFull,判断队空IsQueueEmpty。
(2) 生产者消费者:生产者线程生产消息(MyMSG *),放在一个空缓冲区(CircleQueue)中,供消费者线程消费,生产者生产消息(EnQueue),如果缓冲区满(IsQueueFull), 则被阻塞,消费者消费消息(DeQueue),如果缓冲区空(IsQueueEmpty),则被阻塞。线程消息队列就是生产者消费者问题中的缓冲区,而它 的生产者是不限定的,任何线程都可以作为生产者向其中进行EnQueue操作,消费线程则可能是一个,也可能是多个。因此对循环队列的任何操作都要加锁, 以保证线程安全。
PV操作和锁机制的基础都是信号量。下面列出posix标准中给出的有关信号量的操作:
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t * sem);
int sem_trywait(sem_t * sem);
int sem_post(sem_t * sem);
int sem_getvalue(sem_t * sem, int * sval);
int sem_destroy(sem_t * sem);

以下是我的思考:
线程是复杂系统为了实时响应系统中各个方面的需求(上层,下层各个模块都可能),而按照任务类型来划分执行区间的一个方法。每个执行区间都完成一个相对独立的功能,它们有可能互相交互也有可能并不直接关联。但都在操作系统的维系下统一干活。

高级一些的操作系统有所谓的内核线程/进程;以完成更加复杂的内核对象之维护操作或者协调线程动作(具体些?)。简单点的操作系统则只提供了一个API服务,让线程调用完成交互或者状态切换。
因为CPU只有一个,所以用所谓的有限状态让各线程轮流享用之。如果等待资源则为Wait态,如果自动休眠则为睡眠态。基于优先级的状态切换保障了只有最迫切需要CPU的线程被运行。
不过静态优先级非常容易造成所谓优先级反转的现象:低优先级的线程拿到了某个资源,然后被更高优先级的打断,待更更高优先级的任务来到时如果它也需要那个资源,它就不得不等待前面两个都完事才能拿到资源开始运行。
可以让低优先级任务在拿到重要资源后临时提高其优先级至非常高(高于那些可能使用这个资源的所有任务)然后尽快执行完毕以便其他任务不被阻塞。

线程通讯队列是为了方便互相传递信息的,可以传递对象也可以传递指针,一切要看调用约定怎样。有了通讯队列,就很好的解决了N消费者1生产者的矛盾。同时也可以实现非阻塞的异步操作。都阻塞的话实际效率还是很低下的,对用户的响应也会差。
关于线程同步