2012-03-28 17 views
2

Ich habe versucht, meinen Kopf um das Konzept der Semaphoren in C zu wickeln, und ich hatte einige begrenzte Erfolge. Von was ich verstehe, in C, wenn der Wert eines Semaphors ist 0, ein sem_wait() sollte dazu führen, dass Thread blockieren, bis der Wert dieses Semaphor nicht mehr 0 ist.Unerwartete Semaphor Verhalten, Threads Ausführung jenseits von sem_wait()

Mein Problem ist das: Ich habe geschrieben einige sehr schnelle Beispiel-Code (unten), und ich bin mir nicht sicher, warum, aber sobald die Threads erstellt werden, scheinen sie Code jenseits der sem_wait() auszuführen, obwohl der Wert der Semaphore scheint 0. Ich bin mir nicht sicher warum das wäre.

Edit: Nach Perceptions Ratschlag, überprüfte ich den Rückgabewert von sem_wait(), und es scheint, errno auf "Operation Timed Out." Soweit ich das beurteilen kann, sollte dies nicht passieren, wenn ich sem_timedwait() nicht verwende. Immer noch graben ...

Bearbeiten 2: Oop. Hätte meine Ausgabe genauer lesen sollen. Es wird tatsächlich auf "Funktion nicht implementiert" gesetzt.

#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); 
} 

Einige Beispielausgabe:

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

Sie sollten den Rückgabewert von 'sem_wait' testen, um festzustellen, ob der Aufruf tatsächlich erfolgreich war. – Perception

+0

Sie sollten auch den Rückgabewert von 'sem_open()' testen. – caf

Antwort

3

Semaphore bestehen bleiben nach einem Prozess stirbt, wenn Sie speziell sie entkoppeln. Das Verhalten, das Sie sehen, liegt an den Threads, die alte Jobs sem_post 'd an den Semaphor durch einen vorherigen Prozess ziehen. Ihr sem_getvalue Aufruf würde die Existenz dieser alten Jobs anzeigen, wenn der Aufruf tatsächlich funktioniert hat, aber es schlägt fehl und Sie bemerken es nicht, weil Sie den Rückgabewert sem_getvalue nicht überprüfen. Der Errno-Wert "Funktion nicht implementiert" stammt tatsächlich von sem_getvalue, nicht sem_wait.

sem_unlink("semaphore"); 

vor Ihrem Anruf sem_open hinzufügen und das seltsame Verhalten weggeht.

+0

Danke! Ich habe das herausgefunden, aber ich bin zu neu, also konnte ich meine Frage nicht beantworten. – justindhill

Verwandte Themen