OSX和LINUX上POSIX线程之间的区别?

时间:2013-08-21 02:52:02

标签: linux multithreading macos concurrency pthreads

任何人都可以了解以下原因:当在OSX上编译并运行以下代码时,'bartender'线程以似乎随机的方式跳过sem_wait(),然后在Linux上编译并运行机器sem_wait()是否持有线程,直到对sem_post()的相对调用为止,这是预期的?

我目前不仅学习POSIX线程,而且还学习整体并发性,所以绝对欢迎任何评论,提示和见解......

提前致谢。

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>

//using namespace std;

#define NSTUDENTS 30
#define MAX_SERVINGS 100

void* student(void* ptr);
void get_serving(int id);
void drink_and_think();

void* bartender(void* ptr);
void refill_barrel();


// This shared variable gives the number of servings currently in the barrel
int servings = 10;

// Define here your semaphores and any other shared data
sem_t *mutex_stu;
sem_t *mutex_bar;

int main() {
    static const char *semname1 = "Semaphore1";
    static const char *semname2 = "Semaphore2";

    pthread_t tid;

    mutex_stu = sem_open(semname1, O_CREAT, 0777, 0);
    if (mutex_stu == SEM_FAILED)
    {
        fprintf(stderr, "%s\n", "ERROR creating semaphore semname1");
        exit(EXIT_FAILURE);
    }
    mutex_bar = sem_open(semname2, O_CREAT, 0777, 1);
   if (mutex_bar == SEM_FAILED)
    {
        fprintf(stderr, "%s\n", "ERROR creating semaphore semname2");
        exit(EXIT_FAILURE);
    }

    pthread_create(&tid, NULL, bartender, &tid);
    for(int i=0; i < NSTUDENTS; ++i) {
        pthread_create(&tid, NULL, student, &tid);
    }

    pthread_join(tid, NULL);

    sem_unlink(semname1);
    sem_unlink(semname2);

    printf("Exiting the program...\n");
}


//Called by a student process. Do not modify this.
void drink_and_think() {
    // Sleep time in milliseconds
    int st = rand() % 10;
    sleep(st);
}

// Called by a student process. Do not modify this.
void get_serving(int id) {
    if (servings > 0) {
        servings -= 1;
    } else {
        servings = 0;
    }
    printf("ID %d got a serving. %d left\n", id, servings);
}

// Called by the bartender process.
void refill_barrel()
{
    servings = 1 + rand() % 10;
    printf("Barrel refilled up to -> %d\n", servings);
}

//-- Implement a synchronized version of the student
void* student(void* ptr) {
    int id = *(int*)ptr;
    printf("Started student %d\n", id);
    while(1) {
        sem_wait(mutex_stu);
        if(servings > 0) {
            get_serving(id);
        } else {
            sem_post(mutex_bar);
            continue;
        }
        sem_post(mutex_stu);
        drink_and_think();
    }
    return NULL;
}

//-- Implement a synchronized version of the bartender
void* bartender(void* ptr) {
    int id = *(int*)ptr;
    printf("Started bartender %d\n", id);
    //sleep(5);
    while(1) {
        sem_wait(mutex_bar);
        if(servings <= 0) {
            refill_barrel();
        } else {
            printf("Bar skipped sem_wait()!\n");
        }
        sem_post(mutex_stu);
    }
    return NULL;
}

1 个答案:

答案 0 :(得分:2)

第一次运行程序时,您正在创建具有初始值的命名信号量,但由于您的线程永远不会退出(它们是无限循环),您永远不会进行sem_unlink调用来删除这些信号量。如果您终止程序(使用ctrl-C或任何其他方式),信号量仍然会以它们所处的状态存在。所以如果再次运行程序,sem_open调用将成功(因为你不能)使用O_EXCL),但它们不会重置信号量值或状态,因此它们可能处于某种奇怪的状态。

因此,在调用sem_unlink之前,您应确保在程序STARTS时调用sem_open。更好的是,根本不要使用命名信号量 - 使用sem_init来初始化几个未命名的信号量。