消息通信过程可以采取轮询或者中断两种方式,本文尝试对轮询法的一个缺陷做出分析。
一般轮询法的框架:
在一般小程序中采取该方法并没有任何问题,但是,在一个复杂系统中担负底层通信任务的通讯库如果设计成这种方式,则会为编程带来很多困难。
在一个复杂系统中,多线程技术会被广泛采用。显然,上面的循环遇到某个消息就处理某个消息,属于单线程的工作模式。如何使得上面的程序适合多线程处理呢?可以考虑使用信号灯。我们将上面接收数据的线程成为接收线程,使用数据的线程为工作线程。首先工作线程在信号灯上睡眠等待数据,接收线程收到数据后将数据挂入工作线程消息队列,然后唤醒工作线程。到目前为止,我们已经可以发现第一个问题 了:系统中需要维护若干信号灯和若干消息队列。这些工作必须由通信库使用者来维护。随着通信库的用户量越来越大,用户的维护开销也会越来越大。
关于第一个问题,也许还可以苟且忍受。但是,接下来的第二个问题 会让问题更加复杂。考虑这样一种场景:type1和type2两种消息具有依赖关系,而某个功能的实现需要先接收到type1消息,然后接收到type2消息。我们可以让实现次功能的工作线程依次等待两个信号灯即可。但是,如果系统中还存在第三个线程,它也需要使用type1消息呢?此时单一的信号灯已经不能解决问题了!当type1消息到达时,type1消息队列上的信号灯是唤醒原来的工作线程呢还是唤醒第三个线程?这个问题不解决,要么会丢包,要么会让代码内部逻辑混乱。那么,有补救办法吗?有!在上面的消息接收线程中进一步细分消息类型,比如,将type1细分成type1_for_thread_work, type1_for_thread_third。此时,接收线程趋向于混杂。一旦系统中类似情况很多的时候,无论是效率还是代码可维护性,都会受到极大挑战。
解决上面问题的方法有2种:
1、互斥、阻塞地收发数据包
2、采用多端口,不同的while(1){}针对不同的端口。上层应用通过使用不同的端口来避免消息混杂。
下图描述了单一端口发存在的问题,以及多端口的优势。