C系统编程之生产者与消费者

锁可以实现互斥,条件变量可以实现同步。

为了保护共享数据的正确性,我们需要把锁和条件变量联合起来使用,这就是 管程(Monitor) 的作用。

管程将需要保护的一组共享数据封装起来,利用锁与条件变量实现对这些数据的保护,保证同时只有一个函数能够使用这组数据。

对于一个栈(Stack)数据结构来说,如果在多线程的情况下实现 push()pop() 功能,程序就会变得不安全 —— 在一个线程正在调用 push() 时,如果内核切换到另一个线程,另一个线程运行 pop(),那么就可能出现多种不同的结果;更糟糕的是,如果栈里只剩下一个元素,此时有两个线程调用 pop(),我们可能会在两个线程中获得同一个元素。为了避免这种不安全因素,我们利用管程来保护栈的内部状态。

示例程序:

#include <stdlib.h>
#include <pthread.h>

struct stack_entry {
    void *data;
    struct stack_entry *next;
};

struct stack {
    struct stack_entry *head;
    int capacity;
    int count;
    pthread_mutex_t mutex;
    pthread_cond_t is_full;
    pthread_cond_t is_empty;
};

struct stack *new_stack(int capacity) {
    struct stack *my_stack = calloc(1, sizeof(struct stack));
    if (my_stack == NULL) {
        return NULL;
    }
    my_stack->head = NULL;
    my_stack->capacity = capacity;
    my_stack->count = 0;
    pthread_mutex_init(&my_stack->mutex, NULL);
    pthread_cond_init(&my_stack->is_full, NULL);
    pthread_cond_init(&my_stack->is_empty, NULL);
    return my_stack;
}

int push(struct stack *my_stack, void *data) {
    if (pthread_mutex_lock(&my_stack->mutex) != 0) {
        return -1;
    }
    while (my_stack->count == my_stack->capacity) {
        pthread_cond_wait(&my_stack->is_full, &my_stack->mutex);
    }
    struct stack_entry *new_entry = calloc(1, sizeof(struct stack_entry));
    if (new_entry == NULL) {
        return -1;
    }
    new_entry->data = data;
    new_entry->next = my_stack->head;
    my_stack->head = new_entry;
    my_stack->count += 1;
    pthread_cond_signal(&my_stack->is_empty);
    if (pthread_mutex_unlock(&my_stack->mutex) != 0) {
        return -1;
    }
    return 0;
}

void *pop(struct stack *my_stack) {
    if (pthread_mutex_lock(&my_stack->mutex) != 0) {
        return (void *)-1;
    }
    while (my_stack->count == 0) {
        pthread_cond_wait(&my_stack->is_empty, &my_stack->mutex);
    }
    struct stack_entry *top = my_stack->head;
    my_stack->head = top->next;
    void *data = top->data;
    free(top);
    my_stack->count -= 1;
    pthread_cond_signal(&my_stack->is_full);
    if (pthread_mutex_unlock(&my_stack->mutex) != 0) {
        return (void *)-1;
    }
    return data;
}

int main() {
    return 0;
}
原文地址:https://www.cnblogs.com/quanjun/p/14623845.html