【问题标题】:Semaphore behavior differently on OSX/Ubuntu/Soliars, threads executing beyond sem_wait()OSX/Ubuntu/Soliars 上的信号量行为不同,线程执行超出 sem_wait()
【发布时间】:2014-02-16 23:56:47
【问题描述】:

我正在用 C 学习信号量,并关注了这个帖子:Producer Consumer program using semaphores and pthreads

稍作修改(删除消费者线程中的 sleep() 函数调用),程序将在 OSX 上运行超出 sem_wait() 函数。

但是,当我在其他操作系统上测试相同的程序时,sem_wait() 会阻塞线程。这是我编译和运行的操作系统列表。

  • OSX (Darwin Kernel Version 13.0.0 + gcc 4.9/clang-500.2.79)
  • Ubuntu (3.8.0-29-generic + gcc 4.6.3)
  • Solaris (5.10 Generic_147147-26 + gcc 4.2.1)

我的问题是,为什么这些操作系统之间会有如此大的差异?

代码如下:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>  //instead of </usr/include/semaphore.h> in the original thread

// for sleep
#include <unistd.h>

#define BUFF_SIZE   5           /* total number of slots */
#define NP          3           /* total number of producers */
#define NC          3           /* total number of consumers */
#define NITERS      4           /* number of items produced/consumed */

typedef struct
{
    int buf[BUFF_SIZE];   /* shared var */
    int in;               /* buf[in%BUFF_SIZE] is the first empty slot */
    int out;              /* buf[out%BUFF_SIZE] is the first full slot */
    sem_t full;           /* keep track of the number of full spots */
    sem_t empty;          /* keep track of the number of empty spots */

    // use correct type here
    pthread_mutex_t mutex;          /* enforce mutual exclusion to shared data */
} sbuf_t;

sbuf_t shared;


void *Producer(void *arg)
{
    int i, item, index;

    index = (int)arg;


    for (i=0; i < NITERS; i++)
    {

        /* Produce item */
        item = i;

        /* Prepare to write item to buf */

        /* If there are no empty slots, wait */
        sem_wait(&shared.empty);
        /* If another thread uses the buffer, wait */
        pthread_mutex_lock(&shared.mutex);
        shared.buf[shared.in] = item;
        shared.in = (shared.in+1)%BUFF_SIZE;
        printf("[P%d] Producing %d ...\n", index, item);
        fflush(stdout);
        /* Release the buffer */
        pthread_mutex_unlock(&shared.mutex);
        /* Increment the number of full slots */
        sem_post(&shared.full);

        /* Interleave  producer and consumer execution */
        if (i % 2 == 1) sleep(1);
    }
    return NULL;
}

void *Consumer(void *arg)
{
    int i, item, index;

    index = (int)arg;
    for (i=NITERS; i > 0; i--) {
        sem_wait(&shared.full);
        pthread_mutex_lock(&shared.mutex);
        item=i;
        item=shared.buf[shared.out];
        shared.out = (shared.out+1)%BUFF_SIZE;
        printf("[C%d] Consuming  %d ...\n", index, item);
        fflush(stdout);
        /* Release the buffer */
        pthread_mutex_unlock(&shared.mutex);
        /* Increment the number of full slots */
        sem_post(&shared.empty);

        /* Interleave  producer and consumer execution */
        //if (i % 2 == 1) sleep(1); 
        // do not stop, should be blocked by sem_wait() in next run
    }
    return NULL;
}

int main()
{
    pthread_t idP, idC;
    int index;

    sem_init(&shared.full, 0, 0);
    sem_init(&shared.empty, 0, BUFF_SIZE);
    pthread_mutex_init(&shared.mutex, NULL);
    for (index = 0; index < NP; index++)
    {
        /* Create a new producer */
        pthread_create(&idP, NULL, Producer, (void*)index);
    }
    /*create a new Consumer*/
    for(index=0; index<NC; index++)
    {
        pthread_create(&idC, NULL, Consumer, (void*)index);
    }



    pthread_exit(NULL);
}

在 OSX 上输出(使用 gcc -pthread test.c 编译):

[P0] Producing 0 ...
[P2] Producing 0 ...
[P1] Producing 0 ...
[C0] Consuming  0 ...
[C1] Consuming  0 ...
[C2] Consuming  0 ...
[P0] Producing 1 ...
[P2] Producing 1 ...
[P1] Producing 1 ...
[C0] Consuming  1 ...
[C1] Consuming  1 ...
[C2] Consuming  1 ...
[C0] Consuming  0 ...    <-- should be blocked
[C1] Consuming  0 ...
[C2] Consuming  1 ...
[C0] Consuming  1 ...
[C1] Consuming  1 ...
[C2] Consuming  0 ...
[P0] Producing 2 ...     <-- program stopped here for 1s
[P2] Producing 2 ...
[P1] Producing 2 ...
[P0] Producing 3 ...
[P2] Producing 3 ...
[P1] Producing 3 ...

在 Ubuntu 上输出(使用 gcc -pthread test.c 编译):

[P2] Producing 0 ...
[C2] Consuming  0 ...
[P2] Producing 1 ...
[C1] Consuming  1 ...
[P1] Producing 0 ...
[C0] Consuming  0 ...
[P1] Producing 1 ...
[C2] Consuming  1 ...
[P0] Producing 0 ...
[C1] Consuming  0 ...
[P0] Producing 1 ...
[C0] Consuming  1 ...
[P2] Producing 2 ...     <-- program stopped here for 1s
[C2] Consuming  2 ...
[P1] Producing 2 ...
[P1] Producing 3 ...
[C0] Consuming  2 ...
[C0] Consuming  3 ...
[P2] Producing 3 ...
[C2] Consuming  3 ...
[P0] Producing 2 ...
[C1] Consuming  2 ...
[P0] Producing 3 ...
[C1] Consuming  3 ...

在 Solaris 上输出(使用 gcc -pthread -lrt test.c 编译):

[P1] Producing 0 ...
[P2] Producing 0 ...
[P1] Producing 1 ...
[C0] Consuming  0 ...
[C0] Consuming  0 ...
[C0] Consuming  1 ...
[P2] Producing 1 ...
[C1] Consuming  1 ...
[P0] Producing 0 ...
[P0] Producing 1 ...
[C0] Consuming  0 ...
[C1] Consuming  1 ...
[P1] Producing 2 ...     <-- program stopped here for 1s
[P1] Producing 3 ...
[C2] Consuming  2 ...
[C1] Consuming  3 ...
[P2] Producing 2 ...
[P2] Producing 3 ...
[C2] Consuming  2 ...
[C1] Consuming  3 ...
[P0] Producing 2 ...
[P0] Producing 3 ...
[C2] Consuming  2 ...
[C2] Consuming  3 ...

【问题讨论】:

    标签: c multithreading cross-platform semaphore


    【解决方案1】:

    在 OSX 上,您的 sem_init() 返回 -1 并显示“功能未实现”错误。所以你的信号量不工作,你有一个竞争条件。检查:

    int res = sem_init(&shared.full, 0, 0);
    if (res == -1) { 
        perror("sem_open");
        return 1;
    }
    

    请改用 sem_open()、sem_unlink() 和 sem_close()。请参阅:sem_init on OS X

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多