C-如何将三个信号量用于使用共享内存的服务器客户端体系结构



我正在使用客户端程序实现服务器。通信与共享内存一起工作。为了控制对我使用信号量的共同资源的访问。如果客户端是服务器的新手,则服务器为客户端生成ID。客户端保存其ID,并将在其他请求中发送此ID。我正在使用以下代码在服务器和客户端之间进行通信。该解决方案仅适用于一台服务器和一台客户端。

服务器:

#include <semaphore.h>
sem_t* server = sem_open(SEM_1, O_CREAT | O_EXCL, 0600, 1);
sem_t* client = sem_open(SEM_2, O_CREAT | O_EXCL, 0600, 0);
//other stuff
while (!want_quit)
{
  sem_wait(client)
  //get id of client from shared memory or generate id for client
  //get the command from the client via shared memory
  //process command
  //write result back to shared memory
  sem_post(server)
}

客户端:

#include <semaphore.h>
sem_t* s1 = sem_open(SEM_1, 0);
sem_t* s2 = sem_open(SEM_2, 0);
do
{
   //wait for the server
   sem_wait(s1);
   //get result from last command from shared memory
   //send new request to server by writing command into shared memory
   sem_post(s2);
} while (command from shm != CLOSE);

服务器应工作/管理多于一个客户端。我以为我可以通过第三个信号量解决此问题,但是我遇到了僵局问题或客户处理其他客户的结果。

我的第三个信号量的解决方案看起来如下:

服务器:

sem_wait(clients); sem_wait(client); sem_post(server);

客户端:

sem_wait(s1); sem_post(clients); sem_post(server);

如何解决这个挑战?

您对信号的使用不太正确。信号量旨在保护一个或多个共享资源,通常用信号量的计数代表可用的 Resources 的数量。对于共享内存段,您只有一个资源(内存块),因此您应该使用一个具有1个计数的信号量来保护它。

这个单个信号量会协调所有客户端和服务器。客户获取信号量,编写其命令,然后发布信号量。服务器获取此信号量,读取命令并执行所需的任何处理,将结果写回共享内存,然后发布信号量。

但是,正如您发现的那样,这并不协调每个客户端。没有什么可以阻止客户阅读另一个客户的响应。因此,您可以在此处使用另一个信号量,可以将其视为保护与服务器的"通信通道"。同样,这是一个单一的资源,因此它应具有一个信号量,计数为1。

因此,您的完整设计将使用2个信号量,看起来像:

  1. 从共享内存信号量开始,计数为0,一个频道信号量为1。
  2. 服务器等待共享内存信号量。
  3. 客户获取信号量的信号量,减少到0。这阻止了所有其他客户端。
  4. 同一客户端将写入共享内存段并递增信号,解开服务器。
  5. 客户端和服务器根据需要进行通信,按照您需要获取和释放内存信号。
  6. 完成客户端后,它将发布信号频道,解开另一个客户端与服务器通信。

请注意,服务器永远不会获取通信通道信号量。这纯粹是为了协调两个或更多客户。

我还想指出,该解决方案非常混乱。有很多活动部件,还有很多潜在僵局的地方。这是人们使用诸如IPC的管道,插座和消息队列之类的东西的重要部分。您无需担心锁,因为协调融入了通信频道的设计中(读取/写入块),并且每个客户端都有一个与服务器的单独的通信通道。如果您担心性能,则应查看此答案,以表明各种IPC机制在Linux上的速度相同。您可能会在另一种类型的系统上看到不同的结果。

最新更新