2016-12-11 4 views
0

sleeping barber problem을 학교 과제물의 일부로 해결하고있었습니다. 그것은 GDB로 실행할 때 잘 동작하지만 커맨드 라인에서 실행하면 막히게됩니다.GDB에서 프로그램을 실행하면 명령 줄에서 프로그램을 실행했을 때와 다른 결과가 나타납니다.

#include <stdio.h> 
#include <semaphore.h> 
#include <pthread.h> 
#include <stdlib.h> 
#define MAX 5 

int nr_clients, open; 
sem_t sem_open1, sem_clients, sem_chair, sem_number; 

void *Barber(){ 
    sem_wait(&sem_open1); 
    printf("Barber: Opening the shop\n"); 
    open = 1; 
    sem_post(&sem_open1); 
    while(1){ 
     printf("Barber: Sleeping while there is no clients\n"); 
     sem_wait(&sem_clients); 
     sem_wait(&sem_number); 
     if(nr_clients > 0){ 
      sem_post(&sem_number); 
      printf("Barber: starting to work on a client\n"); 
      sem_post(&sem_chair); 
      sleep(1); 
      sem_wait(&sem_number); 
      printf("Barber: Client finished\n"); 
      nr_clients--; 
      sem_post(&sem_number); 
     } else { 
      printf("Barber: Closing the shop\n"); 
      break; 
     } 
    } 
} 


void *Client(void *x){ 
    int i = *((int*)x); 
    printf("%8sClient(%d): I want a haircut\n", "", i); 
    sem_wait(&sem_open1); 
    sem_wait(&sem_number); 
    if(open == 1 && nr_clients < MAX){ 
     sem_post(&sem_open1); 
     printf("%8sClient(%d): entering the shop\n", "", i); 
     nr_clients++; 
     sem_post(&sem_number); 
     sem_post(&sem_clients); 
     sem_wait(&sem_chair); 
     printf("%8sClient(%d): barber is working on me\n", "", i); 
    } else { 
     printf("No more room\n"); 
    } 
} 



int main(int argc, char const *argv[]) 
{ 
    if(sem_init(&sem_open1,0,1) == -1 || sem_init(&sem_clients,0,0) == -1 
     || sem_init(&sem_chair,0,0) == -1 || sem_init(&sem_number,0,1) == -1){ 
     printf("ERROR!\n"); 
     return 1; 
    } 

    int nr_threads = 5+1; 

    pthread_t thr_id[nr_threads]; 

    if(pthread_create(&thr_id[0], NULL, Barber, NULL) != 0) { 
     printf("ERROR!\n"); 
     exit(1); 
    } 

    int numbers[nr_threads-1]; 

    for (int i = 0; i < nr_threads-1; ++i) 
    { 
     numbers[i] = i; 
    } 

    for (int i = 1; i < nr_threads; ++i) 
    { 
     if(pthread_create(&thr_id[i], NULL, Client, &numbers[i-1]) != 0){ 
      printf("ERROR!\n"); 
      exit(1); 
     } 
    } 




    sleep(10); 

    sem_wait(&sem_open1); 
    open = 0; 
    sem_post(&sem_open1); 

    sem_post(&sem_clients); 

    for (int i = 0; i < nr_threads; ++i) 
    { 
     pthread_join(thr_id[i], NULL); 
    } 
} 

이 같은 컴파일 :

gcc -g sleeping_barber.c -o barber -lpthread 

그리고 바로 명령 줄에서 시작이 코드입니다. 명령 줄 출력 :

 Client(4): I want a haircut 
No more room 
     Client(3): I want a haircut 
     Client(2): I want a haircut 
     Client(1): I want a haircut 
     Client(0): I want a haircut 
^C 

그냥 막히게됩니다. GDB에서

나는 다음과 같이 실행 :

(gdb) file barber 
Reading symbols from barber...done. 
(gdb) r 
Starting program: /home/marko/Desktop/barber 

GDB 출력 : 우리의 과제에 설명 된대로

[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 
[New Thread 0x7ffff77f0700 (LWP 2808)] 
Barber: Opening the shop 
Barber: Sleeping while there is no clients 
[New Thread 0x7ffff6fef700 (LWP 2809)] 
     Client(0): I want a haircut 
     Client(0): entering the shop 
Barber: starting to work on a client 
     Client(0): barber is working on me 
[New Thread 0x7ffff67ee700 (LWP 2810)] 
[Thread 0x7ffff6fef700 (LWP 2809) exited] 
     Client(1): I want a haircut 
     Client(1): entering the shop 
[New Thread 0x7ffff5fed700 (LWP 2811)] 
     Client(2): I want a haircut 
     Client(2): entering the shop 
[New Thread 0x7ffff57ec700 (LWP 2812)] 
     Client(3): I want a haircut 
     Client(3): entering the shop 
[New Thread 0x7ffff4feb700 (LWP 2813)] 
     Client(4): I want a haircut 
     Client(4): entering the shop 
Barber: Client finished 
Barber: Sleeping while there is no clients 
Barber: starting to work on a client 
     Client(1): barber is working on me 
[Thread 0x7ffff67ee700 (LWP 2810) exited] 
Barber: Client finished 
Barber: Sleeping while there is no clients 
Barber: starting to work on a client 
     Client(2): barber is working on me 
[Thread 0x7ffff5fed700 (LWP 2811) exited] 
Barber: Client finished 
Barber: Sleeping while there is no clients 
Barber: starting to work on a client 
     Client(3): barber is working on me 
[Thread 0x7ffff57ec700 (LWP 2812) exited] 
Barber: Client finished 
Barber: Sleeping while there is no clients 
Barber: starting to work on a client 
     Client(4): barber is working on me 
[Thread 0x7ffff4feb700 (LWP 2813) exited] 
Barber: Client finished 
Barber: Sleeping while there is no clients 
Barber: Closing the shop 
[Thread 0x7ffff77f0700 (LWP 2808) exited] 
[Inferior 1 (process 2804) exited normally] 

작품.

정보 :

OS -> 분투 - 16.04.1

DEBUGGER -> GNU GDB (우분투 7.11.1-0ubuntu1 ~ 16.04) 7.11.1

+0

프로그램이 제대로 작동합니다. 우분투 16.04/gdb 7.11.1/gcc 5.4.0 – gobrewers14

답변

2

당신은 여러 문제가 당신의 암호.

클라이언트가 Barber 샵에 들어갈 수 없으면 sem_open1sem_client 세마포어를 다시 출시하지 않습니다. 이것이 스레드가 sem_open1을 기다리는 것을 분명히 막는 이유입니다. "내가 이발을 원한다"이후에 출력이 더 이상 없기 때문에 이것을 공제 할 수 있습니다.

처음 시작하면 이 false이기 때문에 첫 번째 스레드가 상점에 들어갈 때 open이 0이어야합니다. 아무도 증가하지 않았으므로 nr_clients은 아직 open 부분이어야합니다.

출력물을 볼 수도 있습니다. Barber가 아직 상점을 열지 않았습니다. 상점을 처음 시도 할 때 다시 시도 할 논리를 추가 할 수 있습니다.

문제의 원인은 스레드가 실행되는 특정 순서를 가정하기 때문입니다. 출력물의 스레드 번호로 쉽게 볼 수 있으므로 예상 한 바가 아닙니다. 어떤 순서로도 의지 할 수는 없습니다.

상점이 열리도록하려면 Barber의 스레드에 다른 스레드를 시작하기 전에 실행할 기회를 제공해야합니다. 이발사를 만든 후 sleep()을 추가하십시오.

마침내 ... 내가 작성한 것으로 타이밍에 관한 결론에 도달하게 될 것입니다. 디버거에서 또는 디버거없이 프로그램을 실행하면 타이밍이 매우 다를 수 있습니다.

+0

의견에 감사드립니다. 마지막 단락은 두 가지 다른 결과를 설명합니다.세마포어로 작업 할 때 명령을 내린 것이 마지막 일이라고 생각합니다. – Marko

+0

네, 특정 순서를 보장 할 수 있다면 세마포어가 필요 없을 것입니다. ;) 그러나 스레드는 동기화를 사용하지 않고 미리 정의 된 순서없이 실행됩니다. 그렇게하지 않으면 스레드가 실행됩니다. – Gerhardh

관련 문제