Неожиданное поведение семафора, потоки выполняются за пределами sem_wait () - PullRequest
2 голосов
/ 28 марта 2012

Я пытался обернуть голову вокруг концепции семафоров в C, и у меня был некоторый ограниченный успех.Из того, что я понимаю, в C, если значение семафора равно 0, sem_wait () должен привести к блокировке этого потока, пока значение этого семафора не перестанет 0. 0. 1001 *

Моя проблема заключается в следующем: Iя написал очень быстрый пример кода (ниже), и я не уверен почему, но как только потоки созданы, они, кажется, выполняют код за пределами sem_wait (), даже если значение семафора, как представляется, равно 0. Я неконечно, почему это так.

Редактировать: в соответствии с рекомендациями Perception, я проверил возвращаемое значение sem_wait (), и он, похоже, устанавливает errno в значение «Timed Out операции».Насколько я могу сказать, это не должно происходить, если я не использую sem_timedwait ().Все еще копаю ...

Правка 2: Уп.Должен был прочитать мой вывод более внимательно.Фактически он устанавливает значение «Функция не реализована».

#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

1 Ответ

3 голосов
/ 28 марта 2012

Семафоры сохраняются после того, как процесс умирает, если вы специально не отсоедините их.Поведение, которое вы видите, связано с тем, что потоки вытягивают старые задания sem_post 'd на семафор с помощью предыдущего процесса.Ваш вызов sem_getvalue покажет существование этих старых заданий, если вызов действительно сработал, но он не работает, и вы не замечаете этого, поскольку не проверяете возвращаемое значение sem_getvalue.Значение errno «Функция не реализована» фактически равно sem_getvalue, а не sem_wait.

Добавьте

sem_unlink("semaphore");

перед вашим вызовом sem_open, и странное поведение пойдетпрочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...