【问题标题】:pthreads + semaphores, why is this not executing properly?pthreads + semaphores,为什么不能正确执行?
【发布时间】:2011-06-19 21:23:19
【问题描述】:

这是我正在处理的任务。它必须使用信号量,而不是互斥体。

#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... 退出 A...
进入C...
进入 D...
退出 B...
退出 D...
退出 C...
进入电子...
进入F...
退出 F...
退出 E...

应该如下图:

对此的任何帮助将不胜感激,但这是一项任务,所以不要开始告诉我以完全不同的方式去做,也不要直接给出答案,只需指出正确的方向即可。

【问题讨论】:

  • 您使用 SysV 信号量而不是 pthreads 互斥体的任何特殊原因?
  • @bdonlan:这些不是 SysV 信号量,它们是 POSIX 信号量,这是一个现代接口,可以很好地与 pthreads 配合使用。 SysV 信号量使用semget() / semop() / semctl()
  • 我明白了。不过,为什么不使用互斥锁呢?

标签: c concurrency pthreads semaphore


【解决方案1】:

你有两个问题。第一个是您只有 一个 信号量,称为foobar,您打开了七次。第二个问题是命名信号量是持久的——它们会一直存在(并保持相同的值),直到您对它们调用sem_unlink()。由于您从不这样做,因此信号量 foobar 很可能以大于零的值开头,来自您的程序的先前运行。

您可以通过使用sem_unlink() 来纠正这些问题,以确保在创建信号量之前不存在信号量,并为每个信号量使用不同的名称。

或者,您应该真正使用未命名的信号量,它们是使用sem_init() 而不是sem_open() 创建的。为此,您需要将abac、...的声明更改为:

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

然后,您将更改所有 sem_post()sem_wait() 调用,以便它们使用 &amp;ab&amp;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...

【讨论】:

  • 这是一个很好的回应,我也对此感到困惑,但它并没有解决我的程序问题。它仍然没有达到我想要的效果。
  • @Matt:当我对您的代码进行建议的更改时,它似乎对我来说可以正常工作 - 请参阅我更新答案末尾的输出。
【解决方案2】:

在您的代码中,A 在使用 ab 打印退出行之前未锁定。

这意味着当它从睡眠中返回时,它可以为所欲为,因为它不依赖于锁或其他任何东西。

您应该使用信号量来阻止其他线程/函数继续执行。 sleep() 只是在您指定的时间内放弃处理器,之后它们可以继续。

注意:

您可能不必使用睡眠。如果无法获得锁,线程将放弃 CPU

【讨论】:

  • 我有点不确定你的意思,如果可能的话,我想要更深入的解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 2022-07-24
相关资源
最近更新 更多