SDService和SDClient的通信设计 -- 使用Event+Memory map file
SDService和SDClient的通信,一开始想到的就是使用socket的方式。但后来想了一下,windows下进程间通信的方法很多,其他方法是否可以呢?socket的通信方式开销比较大阿。于是:
1. 用Mutex+Memory map file(unnamed). 一开始SDService创建一个mutex,然后wait直到SDClient signal这个mutex。然后SDService就从memory map file中读取command,将结果数据填写入memory map file,再signal另外一个mutex通知SDClient。SDClient最终从memory map file中取回数据。Sounds good。Memory map file可以设计成比如前4K用来填写command,4K开始到1M用来存放数据。command和data每次通信都clear一次就OK。
但 是这样做很快就发现了问题:mutex有一个特殊的性质,就是如果使用WaitForSingleObject来等待一个mutex的话,wait函数会 检查当前wait的线程和mutex中存放的线程ID,如果这两个ID相同,则wait函数认为线程在等待本线程已经得到的mutex,为了防止死锁的现 象产生,wait函数会立刻返回,哪怕该mutex当前是nosignal状态。所以,SDService创建了mutex之后,是无法使用wait函数 block,然后等待SDClient的notify的。
2. 用Event+memory map file。Event没有mutex上面所说的那个特性,SDService可以创建一个event然后wait,等待SDClient的 SetEvent的(见附件中的测试程序)。这样SDService创建一个event让SDClient来notify,SDClient也创建一个 event让SDService来notify,这样就形成了同步,可以很好的通信了。
但是即使这样,还是有问题的。就是如果 SDClient启动了多个怎么办?此时,就要求SDService要能得到每个SDClient的event,还要维护多个memory map file,这样才保证每个SDClient和SDService的通信是一一对应的。这就累了。如果这样的话,似乎比较好的办法就是只允许 SDClient启动一个实例。这可以通过kernel object来做到。每次SDClient启动的时候就尝试去open属于自己的那个event kernel object,如果open成功就表示已经有SDClient实例在运行了。
这样就OK了。事实上,我们也只允许SDClient启动一个实例。因为如果启动了两个SDClient,用户在第二个SDClient中change user的话,SDService就要切换到另外一个账号上去,这样会影响到其他SDClient界面的显示。
但 是要说的是,如果SDClient允许启动多个实例的话,那么,socket就成了最佳选择了。因为使用socket,每个来connect的 client都有一个port的概念,这样SDService不需要直到每个client的具体情况,也不需要维护多个通信buffer,只需要 select,然后read,最后write就OK了,简单的很。
1. 用Mutex+Memory map file(unnamed). 一开始SDService创建一个mutex,然后wait直到SDClient signal这个mutex。然后SDService就从memory map file中读取command,将结果数据填写入memory map file,再signal另外一个mutex通知SDClient。SDClient最终从memory map file中取回数据。Sounds good。Memory map file可以设计成比如前4K用来填写command,4K开始到1M用来存放数据。command和data每次通信都clear一次就OK。
但 是这样做很快就发现了问题:mutex有一个特殊的性质,就是如果使用WaitForSingleObject来等待一个mutex的话,wait函数会 检查当前wait的线程和mutex中存放的线程ID,如果这两个ID相同,则wait函数认为线程在等待本线程已经得到的mutex,为了防止死锁的现 象产生,wait函数会立刻返回,哪怕该mutex当前是nosignal状态。所以,SDService创建了mutex之后,是无法使用wait函数 block,然后等待SDClient的notify的。
2. 用Event+memory map file。Event没有mutex上面所说的那个特性,SDService可以创建一个event然后wait,等待SDClient的 SetEvent的(见附件中的测试程序)。这样SDService创建一个event让SDClient来notify,SDClient也创建一个 event让SDService来notify,这样就形成了同步,可以很好的通信了。
但是即使这样,还是有问题的。就是如果 SDClient启动了多个怎么办?此时,就要求SDService要能得到每个SDClient的event,还要维护多个memory map file,这样才保证每个SDClient和SDService的通信是一一对应的。这就累了。如果这样的话,似乎比较好的办法就是只允许 SDClient启动一个实例。这可以通过kernel object来做到。每次SDClient启动的时候就尝试去open属于自己的那个event kernel object,如果open成功就表示已经有SDClient实例在运行了。
这样就OK了。事实上,我们也只允许SDClient启动一个实例。因为如果启动了两个SDClient,用户在第二个SDClient中change user的话,SDService就要切换到另外一个账号上去,这样会影响到其他SDClient界面的显示。
但 是要说的是,如果SDClient允许启动多个实例的话,那么,socket就成了最佳选择了。因为使用socket,每个来connect的 client都有一个port的概念,这样SDService不需要直到每个client的具体情况,也不需要维护多个通信buffer,只需要 select,然后read,最后write就OK了,简单的很。