2012-10-03 89 views
2

我試圖最終解決生產者 - 消費者問題,但我首先需要能夠使用信號量來創建臨界區。我目前遇到的問題是當我運行程序時,關鍵部分有時會有多個進程進入它。我希望在特定時間只有一個進程處於關鍵部分。這是我目前擁有的代碼:C - 多信號叉與信號量

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 

#define MAX 20 

int main(void) 
{ 
    key_t key = 1114; 
    int semid, count, 
     mutex = 0; 


    //Initialize Semaphore Buffers 
    struct sembuf oper0; 

    pid_t waitId; 
    pid_t parentId = getpid(); 

    //Create processes 
    for(count = 0; count < MAX; count++) 
    { 
     if((waitId = fork()) == 0) 
     { 
      break; 
     } 
    } 

    //Create a semaphore set of 3; I will be adding more semaphores 
    if ((semid = semget(key, 3, 0600 | IPC_CREAT)) == -1) { 
     printf("error in semget"); 
     exit(1); 
    } 

    // BINARY/MUTEX - initialize semaphore0 to 1 
    if(semctl(semid, mutex, SETVAL, 1) == -1) 
    { 
     printf("error in semctl"); 
     exit(0); 
    } 

    //Decrement semaphore 0 
    oper0.sem_op = -1; 
    oper0.sem_flg = 0; 
    if (semop(semid, &oper0, 1) == -1) { 
     printf("error decrementing semaphore \n"); 
     exit(1); 
    } 

    printf(" -- CRITICAL SECTION START ----------- \n\n"); 
    printf("%5d %d  %s\n", getpid(), semctl(semid, 0, GETVAL, oper0.sem_num), " -- Semaphore 0"); 
    printf(" -- CRITICAL SECTION END -- \n\n");  

    //Increments semaphore 0 
    oper0.sem_op = 1; 
    oper0.sem_flg = 0; 
    if (semop(semid, &oper0, 1) == -1) { 
     printf("error incrementing semaphore \n"); 
     exit(1); 
    } 

    int i; 
    if(getpid() == parentId) 
    { 
     for(i = 0; i < MAX i++) 
     { 
      wait(&waitId); 
     } 
    } 
    else 
    { 
     exit(waitId); 
    } 

    // Remove semaphore 
    if (semctl(semid, 0, IPC_RMID) == -1) { 
     printf("error in semctl"); 
     exit(1); 
    } 

    return 0; 
} 

下面是一個示例輸出:

-- CRITICAL SECTION START ----------- 

1097 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

-- CRITICAL SECTION START ----------- 

1085 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

-- CRITICAL SECTION START ----------- 

-- CRITICAL SECTION START ----------- 

1095 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

1093 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

-- CRITICAL SECTION START ----------- 

-- CRITICAL SECTION START ----------- 

1087 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

1089 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

-- CRITICAL SECTION START ----------- 

1091 0  -- Semaphore 0 
-- CRITICAL SECTION END -- 

爲什麼旗語一個過程有時會鎖定,其他時候它可以讓兩個進程嗎?

回答

3

因爲你在每個孩子中執行semctl(semid, mutex, SETVAL, 1)。你真的只想做那一次。如果您將fork循環移動到您創建並初始化信號量的位置之後,您可能會發現它看起來好多了。另外,你可能希望在printf之後fflush(stdout)。如果stdout被緩衝,那麼即使緩衝區寫入關鍵部分,輸出仍可能混合在一起。

+0

這很有道理,謝謝!我只是有一個問題來澄清fflush部分。我只需要將fflush(stdout)放在關鍵部分的printf後面,對吧?原因是因爲緩衝區可能無法立即打印,而其他部分可能會在之前打印? –

+0

如果關鍵部分的要點是對stdout進行序列化,那麼在離開臨界區之前應該先進行刷新,並且不要在臨界區之外打印任何內容,這相當於當緩衝區始終爲空時的不變量不在關鍵部分。 (控制檯輸出是行緩衝的,但是如果你重定向到一個文件則不行。) – rici

+0

哦,好的。再次感謝! –