2012-03-28 5 views
2

C에서 세마포어 개념을 중심으로 머리를 감싸려고 노력했지만 몇 가지 제한된 성공을 거두었습니다. 내가 이해하는 C에서 세마포 값이 0이면 sem_wait()는 해당 세마포 값이 더 이상 0이 아닐 때까지 해당 스레드를 차단해야합니다.예기치 않은 세마포어 동작, sem_wait()를 넘어서 실행되는 스레드

내 문제는 다음과 같습니다. 몇 가지 매우 빠른 예제 코드 (아래), 그리고 왜 모르겠지만 일단 스레드가 만들어지면 semawait() 값이 0 인 것처럼 보일지라도 sem_wait() 이상의 코드를 실행하는 것 같습니다. 이것은있을 것입니다.

편집 : Perception의 조언에 따라 sem_wait()의 반환 값을 확인했으며 errno를 "Operation Timed Out"으로 설정 한 것 같습니다. 지금까지 내가 말할 수있는 한, sem_timedwait()를 사용하지 않는다면 이런 일이 일어나서는 안된다. 아직 파고 ...

편집 2 : Oop. 내 출력을 더 자세히 읽어야합니다. 실제로 "구현되지 않은 기능"으로 설정되어 있습니다.

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <semaphore.h> 
#include <errno.h> 

// vars 
int jobsInQueue, currentJob; 
sem_t *semaphore; 
pthread_t threads[10]; 
int runningThreads = 0; 

// prototypes 
void *do_work(void *arg); 
void add_job(); 

int main() 
{ 
    // i for the for loop used to create the threads 
    int i; 

    // counter for jobs in the queue 
    jobsInQueue = 0; 

    // indicator for the current job 
    currentJob = 0; 

    // indicator for whether we have reached the limit imposed in the while loop used for adding jobs 
    int reachedlimit = 0; 

    // create the semaphore 
    semaphore = sem_open("semaphore", O_CREAT, 0600, 0); 

    // get the value of the semaphore and temporarily store it in reachedlimit 
    sem_getvalue(semaphore, &reachedlimit); 

    // print off the value of the semaphore. I think I'm crazy because the threads are executing code 
    // before the semaphore is posted to, but this appears to be zero... 
    fprintf(stderr, "semaphore: %d", reachedlimit); 
    fflush(stderr); 

    // set reachedlimit back to zero because we expect it to be zero below 
    reachedlimit = 0; 

    for(i = 0; i < 10; ++i) 
    { 
     // create a pthread 
     pthread_create(&threads[i], NULL, &do_work, (void *)i); 

     // increment the number of running threads 
     runningThreads++; 
    } 

    // sleep for a couple of seconds just as separator space 
    sleep(2); 

    // while there are threads running 
    while(runningThreads > 0) 
    { 
     // sleep for a tenth of a second 
     usleep(100000); 

     // after that, if there are 1000 or more jobs in the queue, we've reached the number of total jobs we want 
     if(jobsInQueue >= 1000) reachedlimit = 1; 

     // if we haven't reached that, then add another job 
     if(reachedlimit == 0) add_job(); 

     // print that we're still sleeping and the number of jobs in the queue. 
     fprintf(stderr, "Still sleeping. Jobs in queue: %d\n", jobsInQueue); 
     fflush(stderr); 
    } 
} 

void *do_work(void *arg) 
{ 
    // when the thread is created, print this thread's number to the console 
    fprintf(stderr, "I am thread %d.\n", (int)arg); 
    fflush(stderr); 

    // then loop infinitely doing the following... 
    while(1) 
    { 
     // wait until the semaphore's value is no longer zero <-- doesn't seem to do this 
     sem_wait(semaphore); 

     // if we are on the 1000th job, terminate the thread 
     if (currentJob >= 1000) { 
      runningThreads--; 
      fprintf(stderr, "Thread %d terminated", (int)arg); 
      fflush(stderr); 
      pthread_exit((void *)1); 
     } 

     // otherwise, increment the current job counter 
     currentJob++; 

     // tell the console that this thread took a job 
     fprintf(stderr, "Thread %d: I took a job.: %d\n", (int)arg, currentJob); 
     fflush(stderr); 

     // subtract one from the count of jobs in the queue 
     jobsInQueue--; 

     // sleep for at least one second before taking another job 
     sleep(1); 
    } 

    // this will never happen because the while loop will never be broken 
    runningThreads--; 
    return NULL; 
} 

void add_job() 
{ 
    // increment the count of jobs in the queue 
    jobsInQueue++; 

    // print that a job has been added 
    fprintf(stderr, "Job added\n"); 
    fflush(stderr); 

    // post to the semaphore, which should essentially release the job for "processing" if I understand correctly. 
    sem_post(semaphore); 
} 

일부 샘플 출력 : 특별히 연결을 해제하지 않는 한

semaphore: 0 
I am thread 0. 
I am thread 1. 
Thread 0: I took a job.: 1 
I am thread 2. 
I am thread 3. 
Thread 1: I took a job.: 2 
I am thread 4. 
I am thread 5. 
I am thread 6. 
Thread 2: I took a job.: 3 
I am thread 7. 
I am thread 8. 
Thread 3: I took a job.: 4 
I am thread 9. 
Thread 4: I took a job.: 5 
Thread 5: I took a job.: 6 
Thread 6: I took a job.: 7 
Thread 7: I took a job.: 8 
Thread 8: I took a job.: 9 
Thread 9: I took a job.: 10 
Thread 0: I took a job.: 12 
Thread 4: I took a job.: 11 
Thread 5: I took a job.: 13 
Thread 6: I took a job.: 14 
Thread 1: I took a job.: 15 
Thread 8: I took a job.: 17 
Thread 3: I took a job.: 16 
Thread 7: I took a job.: 18 
Thread 2: I took a job.: 19 
Thread 9: I took a job.: 20 
Thread 0: I took a job.: 21 
Thread 1: I took a job.: 22 
Thread 8: I took a job.: 23 
Thread 3: I took a job.: 24 
Thread 5: I took a job.: 25 
Thread 7: I took a job.: 26 
Thread 6: I took a job.: 27 
Thread 2: I took a job.: 29 
Thread 4: I took a job.: 28 
Thread 9: I took a job.: 30 
Job added 
Still sleeping. Jobs in queue: -29 
Job added 
Still sleeping. Jobs in queue: -28 
Job added 
Still sleeping. Jobs in queue: -27 
Job added 
Still sleeping. Jobs in queue: -26 
Job added 
Still sleeping. Jobs in queue: -25 
Job added 
Still sleeping. Jobs in queue: -24 
Job added 
Still sleeping. Jobs in queue: -23 
Job added 
Still sleeping. Jobs in queue: -22 
Job added 
Still sleeping. Jobs in queue: -21 
Thread 3: I took a job.: 31 
Thread 0: I took a job.: 32 
Thread 5: I took a job.: 33 
Thread 2: I took a job.: 34 
Thread 1: I took a job.: 35 
Thread 7: I took a job.: 36 
Thread 9: I took a job.: 37 
Thread 8: I took a job.: 38 
Thread 6: I took a job.: 39 
Thread 4: I took a job.: 40 
Job added 
Still sleeping. Jobs in queue: -30 
Job added 
Still sleeping. Jobs in queue: -29 
Job added 
Still sleeping. Jobs in queue: -28 
Job added 
Still sleeping. Jobs in queue: -27 
Job added 
Still sleeping. Jobs in queue: -26 
Job added 
Still sleeping. Jobs in queue: -25 
+0

'sem_wait'의 반환 값을 테스트하여 호출이 실제로 성공했는지 확인해야합니다. – Perception

+0

또한'sem_open()'의 반환 값을 테스트해야합니다. – caf

답변

3

세마포어는 프로세스 이후 지속 죽는다. 당신이보고있는 동작은 이전 프로세스에 의해 세마포어에 이전 작업 sem_post을 가져 오는 쓰레드 때문입니다. 전화가 실제로 작동하면 sem_getvalue 호출은 이전 작업의 존재를 표시하지만 sem_getvalue의 반환 값을 확인하지 않기 때문에 실패하고 사용자는 눈치 채지 못합니다. "기능이 구현되지 않았습니다."errno 값은 실제로 sem_getvalue에서가 아니라 sem_wait입니다.

sem_open에 전화하기 전에

sem_unlink("semaphore"); 

를 추가하고 이상한 행동은 멀리 갈 것입니다.

+0

감사합니다! 나는 이것을 알았지 만 나는 너무 새로운 멤버이기 때문에 내 질문에 대답 할 수 없었다. – justindhill