2017-12-05 45 views
0

プロセスとSystem V IPCを使用してCでプロデューサ - コンシューマの問題を実装しようとしています。プロデューサコンシューマセマフォの値が正しくありません

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <errno.h> 
#include <time.h> 
#include "sem.h" 
#include "shm.h" 

#define BUFFER_SIZE 9 

int full; 
int empty; 
int mutex; 

struct buff { 
    int queue[BUFFER_SIZE]; 
} *buffer; 

void producer(); 
void consumer(); 

int main() { 

    int parent_pid, pid, i; 

    parent_pid = getpid(); 

    int shmid = allocate_shared_memory(sizeof(*buffer));   
    buffer = (struct buff *) attach_shared_memory(shmid); 

    for (i = 0; i < BUFFER_SIZE; i++) { 
     buffer->queue[i] = 0; 
    } 

    full = sem_allocate(); 
    empty = sem_allocate(); 
    mutex = sem_allocate(); 


    printf("Full %d\n", full); 
    printf("Empty %d\n", empty); 
    printf("Mutex %d\n", mutex); 


    sem_init(full, 0); 
    sem_init(empty, BUFFER_SIZE); 
    sem_init(mutex, 1); 


    printf("Full value %d\n", sem_get_val(full)); 
    printf("Empty value %d\n", sem_get_val(empty)); 
    printf("Mutex value %d\n", sem_get_val(mutex)); 


    srand(time(0)); 

    pid = fork(); 
    if (!pid) { 
     printf("Producer here: %d\n", getpid()); 
     producer(); 
     printf("Full value after prod() %d\n", sem_get_val(full)); 
     return 0; 
    } else printf("Created new producent: %d\n", pid); 

    sleep(1); 

    pid = fork(); 
    if (!pid) { 
     printf("Consumer here: %d\n", getpid()); 
     printf("Full value before cons() %d\n", sem_get_val(full)); //here I always get 0 
     consumer(); 
     return 0; 
    } else printf("Created new consumer: %d\n", pid); 

     while (1) 
    { 
     int status; 
     pid_t done = wait(&status); 
     if (done == -1) 
     { 
      if (errno == ECHILD) break; // no more child processes 
     } 
     else 
     { 
      if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 
       exit(1); 
      } 
     } 
    } 

    if (getpid() == parent_pid) { 
     sem_deallocate(full); 
     sem_deallocate(empty); 
     sem_deallocate(mutex); 
    } 
} 

void producer() { 

    sem_wait(empty); 
    sem_wait(mutex); 
    printf("Producer is producing!\n"); 
    buffer->queue[0]=0; 
    sem_post(mutex); 
    sem_post(full); 
} 


void consumer() { 

    sem_wait(full); 
    sem_wait(mutex); 
    printf("Consumer is consuming!\n"); 
    sem_post(mutex); 
    sem_post(empty); 

} 

int sem_allocate() { 
    return semget(IPC_PRIVATE, 1, IPC_CREAT | 0666); 
} 

void sem_deallocate(int semid) { 

     if (semctl(semid, 0, IPC_RMID, NULL) == -1) 
    { 
     perror("Error releasing semaphore!\n"); 
     exit(EXIT_FAILURE); 
    } 
} 

int sem_init(int semid, int value) { 
    union semun arg; 
    arg.val = value; 
    if (semctl(semid, 0, SETVAL, arg) == -1) { 
     perror("semctl"); 
     return -1; 
    }else return 1; 
} 

int sem_wait(int semid) { 
    printf("Someone is waiting %d\n", semid); 
    struct sembuf sem = { 0, -1, SEM_UNDO }; 
    return semop(semid, &sem, 1); 
} 

int sem_post(int semid) { 
    printf("Someone is posting %d\n", semid); 
    struct sembuf sem = { 0, 1, SEM_UNDO }; 
    return semop(semid, &sem, 1); 
} 

int sem_get_val(int semid) { 
    return semctl(semid, 0, GETVAL, 0); 
} 


int allocate_shared_memory(int size) { 
    return shmget(IPC_PRIVATE, size, IPC_CREAT | SHM_W | SHM_R); 
} 

void deallocate_shared_memory(const void* addr, int shmid) { 
    shmctl(shmid, IPC_RMID, 0); 
} 

void* attach_shared_memory(int shmid) { 
    return shmat(shmid, NULL, 0); 
} 

がsem.h:

#include <sys/types.h> 
#include <errno.h> 

union semun { 
    int val; 
    struct semid_ds *buf; 
    ushort* array; 
}; 


int sem_post(int); 

int sem_wait(int); 

int sem_allocate(); 

void sem_deallocate(int); 

int sem_init(int, int); 

int sem_get_val(int); 
これは私が学び、セマフォがどのように機能するかをテストするために使用していた私のコードの初期バージョン(キュー操作やループ内で実行しても生産者と消費者を実装せず)であります

shm.h:

#include <stdio.h> 
#include <sys/shm.h> 
#include <sys/stat.h> 

int allocate_shared_memory(int size); 

void deallocate_shared_memory(const void* addr, int shmid); 

void* attach_shared_memory(int shmid); 

なぜフルセマフォの消費関数の値を実行する前には0ですか?プロデューサー直後に仕事が終わっても、値は1 ...

私はこの種のトピックには新しいので、状況の明らかな説明があるかもしれませんが、私は何ができ、希望あなたは私を助けることができます。

答えて

0

"フル"セマフォをゼロに初期化します。終了する前にあなたの "子"プロデューサはsemop()SEM_UNDO引数で呼び出すsem_post()関数を呼び出します。

int sem_post(int semid) { 
    printf("Someone is posting %d\n", semid); 
    struct sembuf sem = { 0, 1, SEM_UNDO }; 
    return semop(semid, &sem, 1); 
} 

のsemopのためのUbuntu Linuxのmanページには、SEM_UNDOについては、次の言葉:

...操作がSEM_UNDOを指定した場合、プロセスが終了したとき、それは自動的に 取り消されます。

このことは、「プロデューサー」は、システムを出その後、前出の「フル」にインクリメントバックゼロに設定する(すなわち、それは「完全」デクリメント)増分を「取り消し」。

"フル"セマフォの目的のために、SEM_UNDOを指定しないでください。

関連する問題