2012-03-28 55 views
2

我一直試圖圍繞C語言中信號量的概念進行包裝,並且我取得了一些有限的成功。據我所知,在C中,如果一個信號量的值爲0,sem_wait()應導致該線程阻塞,直到該信號量的值不再爲0.意外的信號量行爲,超出sem_wait執行的線程()

我的問題是這樣的:一些非常快速的示例代碼(下面),我不確定爲什麼,但是一旦線程被創建,他們似乎會執行超出sem_wait()的代碼,即使信號量的值看起來是0.我不知道爲什麼這將是。

編輯:根據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 2012-03-28 01:18:37

+0

你也應該測試'sem_open()'的返回值。 – caf 2012-03-28 02:11:50

回答

3

信號燈堅持死,除非你明確取消它們的鏈接。您看到的行爲是由於線程將舊作業sem_post'd通過先前的進程拖到信號量上造成的。你的sem_getvalue調用會顯示這些舊工作的存在,如果這個調用真的起作用了,但它失敗了,並且你沒有注意到,因爲你沒有檢查sem_getvalue的返回值。 「功能未實現」errno值實際上是從sem_getvalue而不是sem_wait

呼叫之前添加

sem_unlink("semaphore"); 

sem_open和怪異的行爲會自行消失。

+0

謝謝!我明白了這一點,但我太新了一個成員,所以我無法回答我自己的問題。 – justindhill 2012-03-29 19:22:39