2012-03-20 130 views
1

为了做作业,我需要使用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"; 
} 
+2

您无法控制首先运行哪个进程。所以你需要让你的代码做正确的事情。此外,您需要使用某种同步,或者编译器可以自由地优化对'* shm'的访问,导致while循环无止境。 – 2012-03-20 09:23:06

+0

@DavidSchwartz你的观察非常精确。但在这种特殊情况下,即使没有优化,“while”循环确实是无止境的。 – 2012-03-20 10:01:04

回答

1

我测试了这一点,其实服务器进程第一(StockExchangeServer::start2)运行,但问题是在

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

这导致一个无限循环,你是不是给一个机会StockExchangeClient::start2()更改*shm作为父母等待无限期在sem_wait作为孩子从未执行sem_post

而不是可以做一个sem_post在进入循环之前,以便您从sem_wait中释放父项。为此,您需要发送&semStockExchangeServer::start2。可能是将其原型改为StockExchangeServer::start2(sem_t *sem)之类的东西。

但作为sem未命名信号,和2份存在,一个在父母和一个儿童,如果你想同时父母和孩子使用它,你需要使用一个共享内存区域来创建它shmget,然后跨进程访问它。如果你不想所有这些痛苦,你可以切换到命名信号量甚至可以通过不相关的进程访问。 简而言之,未命名的信号通常用于线程(作为线程共享数据)并为进程命名信号量。

此外,由David Schwartz在评论中指出,确保防止while循环的无意优化。举例来说,在循环之前打印出shm的值。

+0

将sem_t指针传递给两个启动函数是一个非常好的主意,但它对无名信号量不起作用,所以我使用named命名改变了未命名的信号量,它起作用。只需更新您的答案和建议即可使用已命名的信号量,因为分叉的进程与它们同步。结果将是一个很好的答案 – onurozcelik 2012-03-21 13:09:13

+0

@onurozcelik我更新了我的答案:) KIndly接受答案,如果它有帮助。 – 2012-03-21 13:57:34