2012-03-20 128 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