C.

#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>

int buf = 0;
sem_t *mutex, *full, *empty;

void *producer(void *arg) {
    while (1) {
        sem_wait(empty); // Wait for an empty slot
        sem_wait(mutex); // Acquire mutex for critical section
        buf++;
        printf("Item produced. Count: %d\n", buf);
        sem_post(mutex); // Release mutex
        sem_post(full); // Signal that an item is available
    }
    return NULL;
}

void *consumer(void *arg) {
    while (1) {
        sem_wait(full); // Wait for an item to be available
        sem_wait(mutex); // Acquire mutex for critical section
        buf--;
        printf("Item consumed. Count: %d\n", buf);
        sem_post(mutex); // Release mutex
        sem_post(empty); // Signal that an empty slot is available
    }
    return NULL;
}

int main() {
    pthread_t producer_thread, consumer_thread;

    // Initialize semaphores
    mutex = sem_open("/mutex", O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1);
    full = sem_open("/full", O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0);
    empty = sem_open("/empty", O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 10);

    // Create producer and consumer threads
    pthread_create(&producer_thread, NULL, producer, NULL);
    pthread_create(&consumer_thread, NULL, consumer, NULL);

    // Join threads (never reached in this example due to infinite loop in threads)
    pthread_join(producer_thread, NULL);
    pthread_join(consumer_thread, NULL);

    // Close and unlink semaphores (optional, but good practice)
    sem_close(mutex);
    sem_close(full);
    sem_close(empty);
    sem_unlink("/mutex");
    sem_unlink("/full");
    sem_unlink("/empty");

    return 0;
}

下面是一些输出:

Item consumed. Count: 1926
Item consumed. Count: 1925
Item consumed. Count: 1924
Item produced. Count: 1933
Item produced. Count: 1924
Item consumed. Count: 1923
Item consumed. Count: 1924
Item consumed. Count: 1923
Item consumed. Count: 1922
Item consumed. Count: 1921
Item consumed. Count: 1920

我把空的sem设为10,所以把它扩展为buf限制. 为什么yields 超过了极限?

一切都是照课本做的. 在macbook air m1上,所以sem_init不能工作,使用sem_open代替

推荐答案

The main issue与脚本似乎是它的信号量操作失败,但程序没有注意认识到这一点. sem_opensew_waitsem_post函数等都通过返回值传递成功/失败信息,事实上很多C函数都是这样做的. 这些信息需要被监控并采取适当的行动,以避免程序不当行为.

这不是以后要补充的. 你应该在第一次编写代码时这样做,因为

  • 此时您正在考虑所需的行为,并且最好准备好决定对各种错误的适当处理

  • 这是代码最有可能存在错误的时候,正确的错误处理可以帮助您识别和诊断

  • 实际上,您可能需要not个人稍后再回来进行所有适当的错误处理.

在这种情况下,缺乏对sem_open()次调用的正确错误处理是一个bug,因为在您的情况下,这种失败很可能发生,当它们发生时,您的程序不会得到它所需要的信号量行为. 对sem_wait()sem_post()调用缺乏正确的错误处理,导致问题表现为神秘的错误行为,而不是信息性诊断.

也就是说,a contributing issue是你的程序不可避免地无法正确管理它的信号量. 使用命名信号量时,必须

  • 采取有效措施,确保只有打算使用它们的过程才使用它们.

    O_CREATO_EXCL标志打开可以防止两个进程都使用相同的信号量,这很有帮助,但它可能会阻止其他进程使用相同名称的信号量. 这对你的特定程序来说是双向的.

  • 适当地管理其可见性和生命周期 .

    这在很大程度上相当于在最合适的时间sem_unlink()次调用它们--这是在您可以确定所有希望打开特定信号量的进程都已经打开之后尽快进行的. 就像取消一个常规文件的链接一样,取消一个信号量的链接并不会 destruct 它,这只是将它从名称空间中分离出来,这样它就不能被更多的进程打开了. 那些已经打开它的用户,或者通过sem_open()以外的方式获得访问权的用户,可以继续使用它,直到关闭它,无论是显式的还是终止的. 系统将自动清理已解除链接的sem,当没有进程将它们打开时.

为大量的函数调用编写错误处理代码会变得繁琐,而更新大量错误处理代码会非常痛苦. 因此,人们使用宏来帮助生成所有错误处理似乎很常见. 这还有一个额外的好处,就是防止程序的主要行为被大量样板错误处理所掩盖. 有很多方法来处理细节,这是其中之一:

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <errno.h>

int buf = 0;
sem_t *mutex, *full, *empty;

#define warn_if(val, cond, context) do { \
    if ((val) cond) { \
        perror("warning: " context); \
    } \
} while (0)

#define exit_if(val, cond, context) do { \
    if ((val) cond) { \
        perror(context); \
        exit(1); \
    } \
} while (0)

#define do_or_die(func, paren_args) { \
    exit_if((func) paren_args, == -1, #func); \
}

#define pt_do_or_die(func, paren_args) { \
    exit_if(errno = (func) paren_args, != 0, #func); \
}

sem_t *create_semaphore(const char *name, unsigned int initial_val) {
    sem_t *sem = sem_open(name, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, initial_val);
    
    exit_if(sem, == SEM_FAILED, "sem_open");
    warn_if (sem_unlink(name), == -1, "sem_unlink");

    return sem;
}

void *producer(void *arg) {
    while (1) {
        do_or_die(sem_wait, (empty)); // Wait for an empty slot
        do_or_die(sem_wait, (mutex)); // Acquire mutex for critical section
        buf++;
        printf("Item produced. Count: %d\n", buf);
        do_or_die(sem_post, (mutex)); // Release mutex
        do_or_die(sem_post, (full)); // Signal that an item is available
    }
    return NULL;
}

void *consumer(void *arg) {
    while (1) {
        do_or_die(sem_wait, (full)); // Wait for an item to be available
        do_or_die(sem_wait, (mutex)); // Acquire mutex for critical section
        buf--;
        printf("Item consumed. Count: %d\n", buf);
        do_or_die(sem_post, (mutex)); // Release mutex
        do_or_die(sem_post, (empty)); // Signal that an empty slot is available
    }
    return NULL;
}

int main() {
    pthread_t producer_thread;
    pthread_t consumer_thread;

    // Initialize semaphores
    mutex = create_semaphore("/mutex", 1);
    full = create_semaphore("/full", 0);
    empty = create_semaphore("/empty", 10);

    // Create producer and consumer threads
    pt_do_or_die(pthread_create, (&producer_thread, NULL, producer, NULL));
    pt_do_or_die(pthread_create, (&consumer_thread, NULL, consumer, NULL));

    // Join threads (never returns in this example due to infinite loop in threads)
    pt_do_or_die(pthread_join, (producer_thread, NULL));
    pt_do_or_die(pthread_join, (consumer_thread, NULL));

    // Close semaphores (optional, but good practice)
    warn_if(sem_close(mutex), == -1, "sem_close");
    warn_if(sem_close(full), == -1, "sem_close");
    warn_if(sem_close(empty), == -1, "sem_close");

    return 0;
}

C++相关问答推荐

如何在C中通过转换为char * 来访问float的字节表示?

如何将一个enum类型类型转换为另一个类型?

如何通过Zephyr(Devicetree)在PR Pico上设置UTE 1?

ISO_C_BINDING,从Fortran调用C

C:gcc返回多个错误定义,但msvc—不""'

intellisense不工作,甚至已经下载了c/c++扩展

ATTiny1606定时器TCA 0中断未触发

为什么I2C会发送错误的数据?

LONG_DOUBLE_T是否存在(标准C:C23)

正确的TCP/IP数据包 struct

fwrite无法写入满(非常大)缓冲区

使用双指针动态分配和初始化2D数组

Linux不想运行编译后的文件

为什么我的Hello World EFI程序构建不正确?

如何只获取字符串的第一个单词,然后将其与c中的另一个单词进行比较?

无法识别C编程语言的语法,如书中所示

如何摆脱-WIMPLICIT-Function-声明

如何组合两个宏来初始化C语言中的字符串数组?

";错误:寄存器的使用无效;当使用-masm=intel;在gcc中,但在AT&;T模式

在列表中查找素数