一、进程调度方法
1.FIFO:先进先出队列法。一个最高优先级的线程可以一直执行到结束或是主动放弃CPU。高优先级的线程可以随时中断低优先级的线程,获得CPU的使用权限,与之相同优先级的CPU也只能等待其交出CPU的使用权限后才能按排队的顺序先后执行。
2.Round Robin:循环法。除了对于最高的相同优先级的使用时间片轮转的方法外,其他特点与FIFO法相同。注意此处的时间片轮转与windows的不一样,是随时可以被高优先级任务抢占的。
二、进程间通信
QNX所有功能实现都是靠消息传递的机制实现的,并可以轻松实现网络通信。其中POSIX函数与底层的通信就是靠消息实现的。
通信的过程分为三个步骤:client向server发送消息;server向client接受消息;server处理并将结果返回给client。
A useful minimal set of functions is ChannelCreate(),ConnectAttach(),MsgReply(),MsgSend(), and MsgReceive().
对于client想要与server通信要通过ConnectAttach 与server建立连接,使用MsgSend向server发送一个消息。
对于server:
首先要通过ChannelCreate创建一个通道,然后有“receive”和“reply”两个阶段来处理消息。
chid = ChannelCreate (0);或者(Name_attach_t *attach = name_attach(NULL,(char *)”myserver”,0);)
rcvid = MsgReceive (chid, message, sizeof (message),NULL);
MsgReply (rcvid, EOK, message, sizeof (message));
对于client:
需要做两件事情,一是要通过ConnetAttach与server的channel建立连接,二是要通过MsgSend向server发送消息。
1)与server建立连接
int ConnectAttach (int nd,
pid_t pid,
int chid,
unsigned index,
int flags);
例如coid = ConnectAttach (0, 77, 1, 0, 0);是连接了自己节点(0)的,进程号为77的一个进程的1号channel。可是如何获得server的ND/PID/CHID这几参数呢?
QNX提供了几种方法:
1.server向一个文件中写入自己的ND/PID/CHID参数,client发送消息时打开文件,读出字符串。(文件过多)
2.使用全局变量来存储这几个参数。(非常有局限性,如果有共享内存,无法使用网络连接到!)
3.使用命名功能来把client注册一个名字。
4.把server升级为一个resource manger,这样就可以打开/dev/**来建立通信消息。(一般不这样做)。
在通常情况下,命名功能name_attach() and name_open()来完成比较方便。
比如:server_coid = name_open((char *)”myserver” ,0);来打开server创建的/dev/name/local/myserver,与server创建的channel建立连接。
在server端可以使用name_attach()在命名空间创建一个name,如
Name_attach_t *attach = name_attach(NULL,(char *)”myserver”,0);当server的线程结束时,此命名也自动地跟着删除掉。这就很好的解决了建立通道的问题。
2)向server发送消息
这里可以分为几种情况,需要回复数据、回复成功或失败但是不回复数据。于是我们可以使用一下函数完成功能。
int MsgSend (int coid, const void *smsg, int sbytes, void *rmsg, int rbytes);
MsgReply (rcvid, EOK, NULL, 0); //successful
MsgError (rcvid, EROFS); //failed
Client和Server各参数之间的关系如下图所示:
我做了一个这样的实验,在工程中建立一个名为server的工程和一个名为client的工程,两个进程之间完全时陌生的,通过name_attach和name_open的方式建立通道,这样就不需要获得ND/PID/CHID这几个参数了。在实验的过程中发现使用消息进行通信时非常方便的,但是最好自己定义一个命令消息格式,滤除掉不是原client发来的消息(系统还会对server发送消息进行控制),这样就不会出现误触发。
建立一个结构体
Struct _io_message{
Int nbyte;
Int type;
Char msg[1024];
};
就可以很方便的判断传入消息的大小、消息类型以及消息的多少了,如果server的接收buffer太小,使得接收的数据丢失,可以通过判断实际传过来的nbyte和定义buffer的大小来判断这一情况,使用MsgRead()和MsgWrite()再把实际大小的数据读回来。