2017-05-10 10 views
-1

왜 내 코드 디스플레이의 출력의 처음 몇 반복에 대해 소비자가 처음 두 항목을 소비해야 할 때 두 번 소비합니까? 여기C 생산자 소비자 세마포어를 사용하여

Consumer consumes 0 
Producer produces 17 
Producer produces 17 
Consumer consumes 0 
Producer produces 10 
Producer produces 12 
Consumer consumes 10 
Producer produces 11 
Producer produces 43 
Consumer consumes 12 
Producer produces 33 
Producer produces 39 
Consumer consumes 11 

#define N 10 

typedef int semaphore; 
semaphore mutex, full, empty; 

int first=0,last=0, semArray[N]; 

를 표시하는 내 코드의 일부입니다 그 전역 변수의 사용을 수 있을까?

int produce_item(){ 
    int item = rand()%50 +1; 
    printf("Producer produces %d\n",item); 
    sleep(1); 
    return item; 
} 

void consume_item(int item){ 
    printf("Consumer consumes %d\n",item); 
    sleep(2); 
} 

int remove_item(){ 
    int temp = semArray[first]; 
    first = first +1; 
    return temp; 
} 

void insert_item(int item){ 
    semArray[last] = item; 
    last++; 
} 

는 세마포어

에 대한 생산자와 소비자 기능입니다
void* consumer(void* arg) { 
    int item, i=0; 
    while(1){ 
     down(full); 
     down(mutex); 
     item = remove_item(); 
     up(mutex); 
     up(empty); 
     consume_item(item); 
    } 
    return 0; 
} 

void* producer(void* arg) { 
    int item, i=0; 
    while(1){ 
     item=produce_item(); 
     down(empty); 
     down(mutex); 
     insert_item(item); 
     up(mutex); 
     up(full); 
    } 
    return 0; 
} 

void down(semaphore s){ 
    setSemaphore(s,0,-1); 
} 

void up(semaphore s){ 
    setSemaphore(s,0,1); 
} 


int setSemaphore(int semID, int semNum, int semOp){ 
    struct sembuf Buf; 
    Buf.sem_num = semNum; 
    Buf.sem_op = semOp; 
    Buf.sem_flg = 0; 
    return semop(semID,&Buf,1); 
} 
main() { 
    int i; 
    pthread_t threads[2]; 
    srand(time(NULL)); 
    int semid_full, semid_empty, semid_mutex; 

    key_t key; 
    key = ftok("task2.c", 'J'); 

    //initialize and create each semaphore set 
    semid_empty = semget(key, 1, 0600|IPC_CREAT); 
    arg.val = N; 
    semctl(semid_empty, 0, SETVAL, arg); 
    semid_full = semget(key, 1, 0600|IPC_CREAT); 
    arg.val = 0; 
    semctl(semid_empty, 0, SETVAL, arg); 
    semid_mutex = semget(key, 1, 0600|IPC_CREAT); 
    arg.val = 1; 
    semctl(semid_mutex, 0, SETVAL, arg); 

     pthread_create(&threads[0],NULL,consumer,NULL); 
    pthread_create(&threads[1],NULL,producer,NULL); 
     //remove 
    semctl(semid_empty, 0 , IPC_RMID, arg); 
    semctl(semid_full, 0, IPC_RMID,arg); 
    semctl(semid_mutex, 0 , IPC_RMID, arg); 
    for(i=0; i<2; i++) { 
     pthread_join(threads[i],NULL); 
    } 
+1

[MCVE]를 제공해주십시오. 현재 예제는'main()'함수를 포함하지 않고'up()'과'down()'을 구현하지도 않는다. (세마포어에'typedef '를 주면된다. – EOF

답변

1

이 코드가 작동합니다 어떤 희망이되기 전에 해결해야 할 몇 가지 분명 문제가 있습니다

  1. semid_empty은 , semid_emptysemid_empty과 같음 세마포 집합이므로 모든 semop() 작업은 동일한 세마포어에서 작동합니다.
  2. 코드는 생성자 및 소비자 스레드를 만든 후 즉시 세마포 집합을 제거합니다. 모든 후속 semop()에 대한 호출은 실패합니다.
  3. semid_full을 0으로 초기화하려고 시도하면 코드는 세마포어 ID로 잘못 semid_empty을 잘못 사용합니다.

이 항목 1 해결할 수있는 몇 가지 방법이 있습니다 : 세마포어 동일한 프로세스에서만 사용되기 때문에

  • 는 각 세마포어 세트에 대해 서로 다른 키를 사용 또는, 당신은 단순히 IPC_PRIVATE을 사용할 수 있습니다 을 키로 사용하십시오.

    semid_empty = semget(IPC_PRIVATE, 1, 0600|IPC_CREAT); 
    

    이렇게하면 각 세마포 집합이 고유하게됩니다.

  • 동일한 세트에서 3 개의 세마포를 만들고 빈 세마포, 전체 세마포 및 뮤텍스 세마포로 역할을 할당하십시오. 이 semop(), semctl 호출의 수의에 의해

이 항목이 문제를 해결하려면, 등 관련 세마포어 참조 :

  • 세마포어를 제거하지 마십시오. 세마포어는 프로그램 실행간에 필요에 따라 다시 작성되거나 재사용됩니다. 모든 것이 제대로 초기화 될 때마다 적절히 초기화됩니다. 또는
  • 프로세스가 종료 될 때 제거 될 세마포를 구성합니다. 은 신호 또는 다른 방법을 사용할 수 있습니다.

항목 (3)으로 수정, 아마 오타입니다 : 마지막으로

semctl(semid_full, 0, SETVAL, arg); 

, 이것은, 추가 오류 검사 및 코드에 로깅 매우 중요하다; 이러한 문제의 대부분은 즉각적으로 나타났습니다. 특히 semop() 개의 오류가 setSemaphore()에 발생했습니다. 이것은 당신이 스스로 문제를 발견하게 만들었을 것입니다.

위의 코드를 수정하면 모든 코드 문제가 해결되거나 알고리즘이 올바르지는 않겠지 만 시작일 뿐이므로 디버깅 로깅 및 오류 검사를 추가하여 다른 숨겨진 문제를 해결할 수 있습니다.