2

任何人都可以解释当下面的代码在 OSX 上编译和运行时,“调酒师”线程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;
}
4

1 回答 1

2

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

所以你应该确保sem_unlink在程序开始时调用,然后再调用sem_open. 更好的是,根本不要使用命名信号量——用它sem_init来初始化几个未命名的信号量。

于 2013-08-21T04:42:31.670 回答