共享内存与信号量同步

Shared memory synchronization with semaphores

本文关键字:同步 信号量 内存 共享      更新时间:2023-10-16

对于家庭作业,我需要使用IPC。我为共享内存写了一些代码,但它并不能按我的意愿工作。我希望服务器进程在客户端之前运行。我做错了什么?如何修复?

//main.cpp
#include "stockexchangeserver.h"
#include "stockexchangeclient.h"
#include <semaphore.h>
int main(int argc,char *argv[])
{
   StockExchangeServer server;
   StockExchangeClient client;
   pid_t   pid;
   sem_t sem;
   int pshared = 1;
   unsigned int value = 0;
   sem_init(&sem,pshared,value);
   if ((pid = fork()) < 0) {
       std::cout<<"fork errorn";
    } else if (pid > 0) {
       sem_wait(&sem);
       client.start2();
       sem_post(&sem);
    } else {
       server.start2();
       sem_post(&sem);
    }
   return 0;
}
   //stockexchangeclient.cpp
   void StockExchangeClient::start2() {
    int sharedMemoryId;
    key_t key;
    int *shm;
    key = 6000;
    if((sharedMemoryId = shmget(key,sizeof(int),0666)) < 0) {
        std::cout<<"Shared memory create errorn";
        exit(1);
    }
    else{}
    if((shm = (int *)shmat(sharedMemoryId,NULL,0)) == (int *)-1) {
        std::cout<<"Shared memory attach errorn";
        exit(1);
    }
    else{}
    *shm = 1;
    exit(0);
}
//stockexchangeserver.cpp
void StockExchangeServer::start2()
{
    int sharedMemoryId;
    key_t key;
    int *shm;
    key = 6000;
    if((sharedMemoryId = shmget(key,sizeof(int),IPC_CREAT | 0666)) < 0) {
        std::cout<<"Shared memory create errorn";
        exit(1);
    }
    else{}
    if((shm = (int *)shmat(sharedMemoryId,NULL,0)) == (int *)-1) {
        std::cout<<"Shared memory attach errorn";
        exit(1);
    }
    else{}
   *shm = 0;
    while(*shm == 0) {
        sleep(1);
    }
    std::cout<<"Shared memory succededn";
}

我对此进行了测试,事实上服务器进程首先运行(StockExchangeServer::start2),但问题出在中

while(*shm == 0) {
    sleep(1);
}

这导致了一个无限循环,并且您没有给StockExchangeClient::start2()更改*shm的机会,因为父级在sem_wait无限期等待,因为子级从未执行sem_post

相反,可以在进入StockExchangeServer::start2中的循环之前执行sem_post,以便从其sem_wait中释放父级。为此,您需要将&sem发送到StockExchangeServer::start2。可能是通过将其原型更改为类似StockExchangeServer::start2( sem_t *sem )的东西。

但是,由于sem是一个未命名的信号量,并且存在两个副本,一个在父级,一个位于子级,如果您希望父级和子级都使用它,则需要使用shmget在共享内存区域中创建它,然后跨进程访问它。如果您不想所有这些痛苦,您可以切换到命名信号量,甚至可以由不相关的进程访问简而言之,未命名信号量通常用于线程(因为线程共享数据),而命名信号量用于进程

正如David Schwartz在评论中所观察到的,确保防止while循环的意外优化。例如,在循环之前打印出shm的值。