pthreads + семафоры, почему это не выполняется должным образом? - PullRequest
4 голосов
/ 20 июня 2011

Это задание, над которым я работаю. Он должен использовать семафоры, а не мьютекс.

#include <stdio.h> 
#include <pthread.h> 
#include <assert.h> 
#include <unistd.h> 
#include <semaphore.h> 
#include <fcntl.h>
sem_t *ab, *ac, *ad, *de, *ce, *bf, *ef; 

void *a(void *arg) {
    printf("Entering A...\n");
    sleep(1);
    printf("Exiting A...\n");
    assert(sem_post(ab)==0);
    assert(sem_post(ac)==0);
    assert(sem_post(ad)==0);
    pthread_exit((void *)99);
}

void *b(void *arg) {
    assert(sem_wait(ab)==0);
    printf("Entering B...\n");
    sleep(1);
    printf("Exiting B...\n");
    assert(sem_post(bf)==0);
    pthread_exit((void *)99);
}

void *c(void *arg) {
    assert(sem_wait(ac)==0);
    printf("Entering C...\n");
    sleep(1);
    printf("Exiting C...\n");
    assert(sem_post(ce)==0);
    pthread_exit((void *)99);
}

void *d(void *arg) {
    assert(sem_wait(ad)==0);
    printf("Entering D...\n");
    sleep(1);
    printf("Exiting D...\n");
    assert(sem_post(de)==0);
    pthread_exit((void *)99);
}

void *e(void *arg) {
    assert(sem_wait(ce)==0);
    assert(sem_wait(de)==0);
    printf("Entering E...\n");
    sleep(1);
    printf("Exiting E...\n");
    assert(sem_post(ef)==0);
    pthread_exit((void *)99);
}

void *f(void *arg) {
    assert(sem_wait(bf)==0);
    assert(sem_wait(ef)==0);
    printf("Entering F...\n");
    sleep(1);
    printf("Exiting F...\n");
    pthread_exit((void *)99);
}


int main() { 
    pthread_t _a, _b, _c, _d, _e, _f;
    int r1, r2, r3, r4, r5, r6;

    ab=sem_open("foobar", O_CREAT, 0700, 0);
    ac=sem_open("foobar", O_CREAT, 0700, 0);
    ad=sem_open("foobar", O_CREAT, 0700, 0);
    ce=sem_open("foobar", O_CREAT, 0700, 0);
    de=sem_open("foobar", O_CREAT, 0700, 0);
    ef=sem_open("foobar", O_CREAT, 0700, 0);
    bf=sem_open("foobar", O_CREAT, 0700, 0);

    /*sem_init(ab,0,1);
    sem_init(ac,0,1);
    sem_init(ad,0,1);
    sem_init(ce,0,1);
    sem_init(de,0,1);
    sem_init(ef,0,1);
    sem_init(bf,0,1);*/

    assert(pthread_create(&_a, NULL, a, &r1) == 0);
    assert(pthread_create(&_b, NULL, b, &r2) == 0);
    assert(pthread_create(&_c, NULL, c, &r3) == 0);
    assert(pthread_create(&_d, NULL, d, &r4) == 0);
    assert(pthread_create(&_e, NULL, e, &r5) == 0);
    assert(pthread_create(&_f, NULL, f, &r6) == 0);

    assert(pthread_join(_a, NULL) == 0);
    assert(pthread_join(_b, NULL) == 0);
    assert(pthread_join(_c, NULL) == 0);    
    assert(pthread_join(_d, NULL) == 0);
    assert(pthread_join(_e, NULL) == 0);
    assert(pthread_join(_f, NULL) == 0);

    assert( sem_close(ab)==0 ); 
    assert( sem_close(ac)==0 ); 
    assert( sem_close(ad)==0 ); 
    assert( sem_close(ce)==0 );
    assert( sem_close(de)==0 ); 
    assert( sem_close(bf)==0 );
    assert( sem_close(ef)==0 ); 

    return 0; 
}

Это довольно просто, но по некоторым причинам это не выполняется в правильном порядке. Вывод далеко не последовательный, но всегда неверный. Вот один пример вывода:

Ввод A ...
Ввод B ... <---- sem_post (ab) еще даже не вызывался <br> Выход из A ...
Ввод C ...
Ввод Д ...
Выход из B ...
Выход из D ...
Выход из C ...
Ввод E ...
Ввод F ...
Выход из F ...
Выход из E ...

Это должно следовать следующей схеме:

image

Любая помощь в этом будет принята с благодарностью, но это задание, поэтому не начинайте говорить мне делать это совершенно по-другому и не давать ответ прямо, просто направьте меня в правильном направлении.

Ответы [ 2 ]

2 голосов
/ 20 июня 2011

У вас две проблемы. Во-первых, у вас есть только один семафор, называемый foobar, который вы открываете семь раз. Вторая проблема заключается в том, что именованные семафоры являются постоянными - они остаются (и сохраняют одно и то же значение) до тех пор, пока вы не вызовете для них sem_unlink(). Поскольку вы никогда этого не делаете, вполне вероятно, что семафор foobar начинается со значения, большего нуля, с предыдущего запуска вашей программы.

Вы можете исправить эти проблемы, используя sem_unlink(), чтобы убедиться, что семафоры не существуют до их создания, и используя другое имя для каждого семафора.

В качестве альтернативы вам следует использовать неназванные семафоры, которые создаются с sem_init() вместо sem_open(). Для этого вы должны изменить декларации ab, ac, ... на:

sem_t ab, ac, ad, de, ce, bf, ef;

Затем вы измените все вызовы sem_post() и sem_wait(), чтобы они использовали &ab, &ac, ...:

void *a(void *arg) {
    printf("Entering A...\n");
    sleep(1);
    printf("Exiting A...\n");
    assert(sem_post(&ab)==0);
    assert(sem_post(&ac)==0);
    assert(sem_post(&ad)==0);
    pthread_exit((void *)99);
}

Вы бы заменили sem_open() звонки на sem_init():

sem_init(&ab, 0, 0);
sem_init(&ac, 0, 0);
sem_init(&ad, 0, 0);
sem_init(&ce, 0, 0);
sem_init(&de, 0, 0);
sem_init(&ef, 0, 0);
sem_init(&bf, 0, 0);

И, наконец, замените sem_close() вызовы на sem_destroy():

assert( sem_destroy(&ab)==0 );
assert( sem_destroy(&ac)==0 );
assert( sem_destroy(&ad)==0 );
assert( sem_destroy(&ce)==0 );
assert( sem_destroy(&de)==0 );
assert( sem_destroy(&bf)==0 );
assert( sem_destroy(&ef)==0 );

Когда я делаю вышеуказанные изменения в вашем коде, я получаю следующий вывод, который, как я полагаю, соответствует вашим ожиданиям:

Entering A...
Exiting A...
Entering B...
Entering C...
Entering D...
Exiting B...
Exiting C...
Exiting D...
Entering E...
Exiting E...
Entering F...
Exiting F...
0 голосов
/ 20 июня 2011

В вашем коде A не заблокирован перед печатью строки выхода с ab .

Это означает, что когда он возвращается из спящего режима, он может делать все, что хочет, потому что он не зависитна блокировку или что-то еще.

Вы должны использовать семафоры, чтобы остановить продолжение других потоков / функций.sleep () просто отдает процессору указанное вами время, после чего они могут продолжить работу.

Примечание:

Возможно, вам не нужно использовать sleep.потоки откажутся от процессора, если не смогут получить блокировку

...