Синхронизация общей памяти с семафорами - PullRequest
1 голос
/ 20 марта 2012

Для домашней работы мне нужно использовать 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 error\n";
    } 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 error\n";
        exit(1);
    }
    else{}

    if((shm = (int *)shmat(sharedMemoryId,NULL,0)) == (int *)-1) {
        std::cout<<"Shared memory attach error\n";
        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 error\n";
        exit(1);
    }
    else{}
    if((shm = (int *)shmat(sharedMemoryId,NULL,0)) == (int *)-1) {
        std::cout<<"Shared memory attach error\n";
        exit(1);
    }
    else{}
   *shm = 0;
    while(*shm == 0) {
        sleep(1);
    }
    std::cout<<"Shared memory succeded\n";
}

1 Ответ

1 голос
/ 20 марта 2012

Я проверял это, и фактически серверный процесс запускается первым (StockExchangeServer::start2), но проблема в

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

Это приводит к бесконечному циклу, и вы не можете StockExchangeClient::start2() изменить *shm, поскольку родитель ожидает неопределенно в sem_wait, так как ребенок никогда не выполнял sem_post

Вместо этого можно сделать sem_post перед входом в цикл в StockExchangeServer::start2, чтобы вы освободили родителя от его sem_wait. Для этого вам необходимо отправить &sem на StockExchangeServer::start2. Может быть, изменив его прототип на что-то вроде StockExchangeServer::start2( sem_t *sem ).

Но поскольку sem является безымянным семафором , существует 2 копии, одна на родительском и одна на дочернем, и если вы хотите, чтобы его использовали и родительский, и дочерний, вам необходимо создать его в область общей памяти, используя shmget, а затем доступ к ней через процессы. Если вам не нужна вся эта боль, вы можете переключиться на именованные семафоры , к которым могут обращаться даже не связанные процессы. Короче говоря, безымянные семафоры обычно используются для потоков (поскольку потоки совместно используют данные) и именованные семафоры для процессов.

Также, как заметил Дэвид Шварц в комментариях, убедитесь, что вы предотвращаете непреднамеренную оптимизацию цикла while. Например, перед циклом выведите значение shm.

...