2014-02-16 15 views
1

我正在学C语言信号,并遵循以下主题:Producer Consumer program using semaphores and pthreadsOSX/Ubuntu/Soliars上的信号量行为不同,线程执行超出sem_wait()

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

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

  • OSX(达尔文内核版本13.0.0 + GCC 4.9 /铛-500.2.79)< --tried两者有同样的问题
  • Ubuntu的(3.8.0-29泛型+ 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上(使用编译210):

[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 ... 

回答

1

在OSX上,您的sem_init()返回-1且“Function not implemented”错误。所以你的信号灯不工作,你有竞争条件。检查:

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