在QNX Neutrino中消息传递(Message passing)是IPC的主要形式,其他形式也都是基于消息传递来实现的。QNX中提供了如下一个形式的IPC:
Serive: Implemented in:
・Message-passing Kernel
・Signals Kernel
・POSIX message queues External process
・Shared memory Process manager
・Pipes External process
・FIFOs External process
一、Synchronous message passing[同步消息传递]
如果一个线程执行了MsgSend()方法向另一个线程(可以属于不同进程)发送消息,它会就被阻塞,直到目标线程执行了MsgReceive(),并处理消息,然后执行了MsgReply()。如果一个线程在其他线程执行MsgSend()之前执行了MsgReceive(),它会被阻塞直到另一个线程执行了MsgSend()。消息传递是通过直接的内存copy来实现的。需要巨大消息传递的时候建议通过Shared Message[共享内存]或其他方式来实现。
1、消息传递中的状态迁移
客户程序的状态迁移
・SEND blocked:调用MsgSend()后,服务程序没有调用MsgReceive()的状态。
・REPLY blocked:调用MsgSend()后,并且服务程序调用了MsgReceive(),但是没有调用MsgReply()/MsgError()的状态。当服务程序已经调用了MsgReceive()方法是,客户程序一旦调用MsgSend()就直接迁移如REPLY blocked状态。
・READY:调用MsgSend()后,并且服务程序调用了MsgReceive()和MsgReply()的状态。
服务程序的状态迁移:
・RECEIVE blocked;调用MsgReceive()后,客户程序没有调用MsgSend()时的状态。
・READY:消息处理时的状态。MsgReply()调用后不回阻塞。当服务程序已经中止时,调用MsgSend()会返回一个错误,不会被阻塞。
2、Channels and connections[渠道与连接]
在QNX Neutrino中消息传递是通过Channels和Connections的,而不是直接在线程之间传递。一个要接受消息的线程必须先生成一个Channel,而一个要发消息的线程必须依附于(Attaching) Channel生成一个Connection。一个进程中的多个客户线程可以同时依附于一个Channel上,这时所有Connection实际上都会映射到同一内核对象。
客户连接直接映射到文件描述符(File Descriptors)。这样客户线程不需要了解向什么地方发送消息,而仅仅需要考虑向文件描述符中发送消息。
一个Channel中包含以下三种列表:
・Receive:一个用来保存等待消息的线程的后进先出队列(LIFO queue)
・Send:一个用来保存已发送但未被接受的优先级先进先出队列(Priority FIFO queue)
・Reply:一个用来保存已被接受但是还没有返回的不排序列表(Unordered List)
所有这些队列中等待的线程都是被阻塞的线程。多个服务线程和多个客户线程可以等待在一个Channel上。
3、Pulses
QNX Neutrino同样提供了被称为Pulses的非同步的消息机制。Pulses通常用于中断处理线程的通知机制,或通过服务线程来唤醒客户现存而不被阻塞。
4、Prority inheritance and messages
当服务线程接收消息时会将服务线程的优先级调整为发送者线程中的最高优先级。如果有以下三个线程,服务线程的优先级为22,客户线程1的优先级为13,客户线程2的优先级为10。客户线程2发送一条消息的话,服务器线程的在接受时会将自身的优先级调整为10。这次客户线程1也发送了一条消息的话,服务器线程的优先级就会调整为13。
这种优先级继承机制的目的是为了防止以下两种优先级逆转。
・当服务线程的优先级较高时,不会因为低优先级的客户线程的消息而抢占比起高优先级线程。
・当服务线程的优先级较低时,一个较高优先级的线程的消息不会被一个较低优先级线程所抢占。
4、Robust implementations with Send/Receive/Reply
通过Send/Receive/Reply实现的程序能够通过以下两条规则避免Deadlock
・永远不要有两个线程相互发消息
・将线程组织为等级结构,并且只向上发消息
二、其他IPC机制
1、Events[事件]
QNX Neutrino提供的一种非同期事件发送机制。以下三种情况下会发送Events
・MsgDeliverEvent()被调用
・中断处理
・计时器到期
(具体的没搞懂)
2、Signals[信号]
信号处理类似于硬件中断,它会使某个进程从当前的执行控制流程中跳出,以实现特定的行为,待特定处理完成后,再恢复到中断点继续执行。QNX Neutrino中的Signals是通过Events机制实现的。QNX Neutrino系统中提供了如下64个Signals:
Signal range Description
・ 1~57 57 POSIX signals
・41~56 16 POSIX 实时Signals(Realtime signals)
・57~54 8个QNX Neutrino特有Signals(Special-purpose signals)
当一个服务线程希望通知一个客户线程一些信息时,可以使用两种手段:
・Pulses:客户线程需要生成一个Channel,并调用MsgReceive()。
・Signals:只需要调用sigwaitinfo(),而不需要生成Channel。
3、POSIX message queues[POSIX的消息队列]
POSIX通过message queues定义一组非阻塞的消息传递机制。QNX Neutrino的系统核心不支持Message queues,如果想使用它就必须启动对应的服务。QNX Neutrino提供了两种Message queues的实现
・mqueue:一个传统的使用mqueue资源管理的实现
・mq:一个使用mq服务和非同步消息的替代实现
QNX的Message机制与POSIX的Message queues有一个根本性的区别,QNX的消息机制通过内存拷贝来实现消息的传递,而POSIX的消息队列通过将消息队列的存取来实现消息的传递,POSIX可以维护多了消息队列。QNX的消息机制比POSIX的消息队列更有效率,但是有时为了POSIX的灵活性,这点性能消耗也是值得的。
4、Shared memory[内存共享]
由于Shared memory不支持内蕴的同期处理,所以通常和Semaphores或Mutexes一起使用。一般来说Semaphores用于进程间同步,而Mutex用于线程间同步。QNX的Mutexes也支持进程间的同步。一般来说Mutexes效率更高。
QNX中的消息传递时通过消息的直接拷贝来完成的,当消息较大时可以通过Shared memory来提升消息。发送消息时,不是发送整个消息,而是将消息保存于Shared memory中,并将地址发送过去,而接收消息时通过Shared memory的地址来读取消息。
5、Typed memory(没搞懂!!)
6、Pipes[管道与先进先出]
Pipe是两个或多个协作进程间的未命名的IO通道。Pipe通常用于两个平行的进程想要单向传输数据,如果是双向的数据传输就应该使用消息。
7、FIFOs[先进先出存储器]
FIFOs是文件系统中的一个已命名的永久文件,实现的功能与Pipes完全一样
免责声明/版权申明 Passiontech
所有文章为网上搜集或私下交流学习之用,任何涉及商业盈利目的均不得使用,否则产生的一切后果由您自己承担!
本站仅仅提供一个观摩学习的环境,将不对任何资源负法律责任。所有资源请在下载后24小时内删除。
若无意中侵犯到您的版权利益,请来信联系我们,我们会在收到信息三天内给予处理!