实际系统中的调度
我们已经谈过调度算法以及线程状态,但是我们还没有说过线程等重新调度的原因与时间。有一个常见的误解就是:重新调度的发生是没有什么原因的。这在设计阶段是一个有用的概念。但是更重要的是你要知道产生重新调度的条件。
重新调度只会由于以下几个原因才会发生:
我们已经谈过调度算法以及线程状态,但是我们还没有说过线程等重新调度的原因与时间。有一个常见的误解就是:重新调度的发生是没有什么原因的。这在设计阶段是一个有用的概念。但是更重要的是你要知道产生重新调度的条件。
重新调度只会由于以下几个原因才会发生:
在编程中你可能注意到你想要能够运行多个线程,并且你也想在某个限度上控制这些线程的行为。例如,在一个服务器中,你可能决定只让一个线程阻塞,等待来自客户端的一个消息。当这个线程获得了消息并开始处理这个请求的时候,你可能需要再创建一个新的线程来等待下一个请求的到来,以便在新的请求到了的时候由这个线程完成相应的处理。如此下来,过了一段时间所有的请求都被处理之后,你就会有多个线程在那里等待后续的客户端请求了。为了保护资源,你可能需要杀掉一些多余的线程。
这其实是一个常见的操作,Neutrino实时系统也提供了一个库来帮助处理这些操作。
现在需要注意的是这些线程池中的线程做了两个不同的操作:
条件变量(condition variables或condvars)与前面讲的睡眠锁(sleepon lock)非常类似。而实际上睡眠锁是在条件变量的基础上构建的,这也是为什么我们在睡眠锁的例子的解释表中有一个CONDVAR状态。它也能通过不停的调用pthread_cond_wait()函数来释放互斥体、等待以及重新获取互斥体,和pthread_sleepon_wait()函数一样。
下面我们就略过初始化的步骤,并使用条件变量来重新完成sleepon部分的那个生产者与消费者的多线程的程序。之后再讨论调用的函数。
我们在前面曾经说过,当多个互相独立的处理算法对同一个共享的数据结构进行处理的时候使用多线程是有用的。严格地说你也可以使用多个进程(每个进程有一个线程)来共享数据,有些情况下使用同一个进程中的多个线程来处理会更简单些。下面说说在哪里以及为什么要使用多线程。
我们的例子里,我们会使用一个标准的输入/处理/输出的模型。通常来说,这个模型的一部分负责从什么地方获取输入,另外一部分负责处理输入并产生某种形式的输出,第三部分则是将输出反馈到什么地方。
先来看看多进程、每个进程一个线程的情况。在这里,我们有三个进程,一个输入进程、一个处理进程和一个输出进程,如下面的示意图所示:
尽管你一般可以忽略你的系统是运行在SMP架构上还是单处理器上,不过还是有些事情会影响到你。不幸的是,这些事情都是低概率事件,它们可能在你的开发阶段没有出现,但是可能在测试、演示或更糟的,在实际应用中出现。在编程的时候花些时间做些防御性的措施可以在后续的阶段减少问题的发生几率。
下面就是你可能在SMP系统上遇到的事情:
近期评论