【问题标题】:Implementing Producer/Consumer Communication实施生产者/消费者沟通
【发布时间】:2015-05-07 14:53:15
【问题描述】:

我正在尝试使用我已经在 C 中实现的信号量和锁通过有界缓冲区实现生产者/消费者通信。我需要让生产者将“hello world”放在一个 5 字节的缓冲区上,一个字符时间。如果缓冲区已满,生产者需要阻塞。我正在努力弄清楚如何将字符串放在缓冲区上。这是我目前所拥有的:

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

#define BUF_SIZE 5

// the buffer works like a stack for
// the sake of simplicity, if needed
// we may implement a queue
 typedef struct {
    int buf[BUF_SIZE]; // the buffer
    size_t len; // number of items in the buffer
    pthread_mutex_t mutex; // needed to add/remove data from the buffer
    pthread_cond_t can_produce; // signaled when items are removed
    pthread_cond_t can_consume; // signaled when items are added
 } buffer_t;

// produce random numbers
void* producer(void *arg) {
    buffer_t *buffer = (buffer_t*)arg;

while(1) {
 #ifdef UNDERFLOW
    // used to show that if the producer is somewhat "slow"
    // the consumer will not fail (i.e. it'll just wait
    // for new items to consume)
    sleep(rand() % 3);
 #endif

    pthread_mutex_lock(&buffer->mutex);

    if(buffer->len == BUF_SIZE) { // full
        // wait until some elements are consumed
        pthread_cond_wait(&buffer->can_produce, &buffer->mutex);
    }

    // in real life it may be some data fetched from
    // sensors, the web, or just some I/O
    int t = rand();
    printf("Produced: %d\n", t);

    // append data to the buffer
    buffer->buf[buffer->len] = t;
    ++buffer->len;

    // signal the fact that new items may be consumed
    pthread_cond_signal(&buffer->can_consume);
    pthread_mutex_unlock(&buffer->mutex);
}

// never reached
return NULL;
}

// consume random numbers
void* consumer(void *arg) {
buffer_t *buffer = (buffer_t*)arg;

while(1) {
#ifdef OVERFLOW
    // show that the buffer won't overflow if the consumer
    // is slow (i.e. the producer will wait)
    sleep(rand() % 3);
 #endif
    pthread_mutex_lock(&buffer->mutex);

    if(buffer->len == 0) { // empty
        // wait for new items to be appended to the buffer
        pthread_cond_wait(&buffer->can_consume, &buffer->mutex);
    }

    // grab data
    --buffer->len;
    printf("Consumed: %d\n", buffer->buf[buffer->len]);

    // signal the fact that new items may be produced
    pthread_cond_signal(&buffer->can_produce);
    pthread_mutex_unlock(&buffer->mutex);
}

// never reached
return NULL;
}

int main(int argc, char *argv[]) {
buffer_t buffer = {
    .len = 0,
    .mutex = PTHREAD_MUTEX_INITIALIZER,
    .can_produce = PTHREAD_COND_INITIALIZER,
    .can_consume = PTHREAD_COND_INITIALIZER
};

pthread_t prod, cons;
pthread_create(&prod, NULL, producer, (void*)&buffer);
pthread_create(&cons, NULL, consumer, (void*)&buffer);

pthread_join(prod, NULL); // will wait forever
pthread_join(cons, NULL);

return 0;
}

【问题讨论】:

  • 看起来不错。您可以让消费者从缓冲区 [0] 中进食,然后 memmove 任何剩余的字节,如下所示: memmove(buffer->buf, buffer->buf + 1, sizeof(int) * buffer->len);此外,您通常希望将 if (!condition_true) 更改为 while (!condition_true) 以处理信号中断以及当您有更多线程时,这很常见。

标签: c unix pthreads buffer producer-consumer


【解决方案1】:

堆栈是后进先出的。不是你想要的。

我会强烈地实现一个带有头尾指针的循环缓冲区。

然后使用互斥锁(不需要信号量)锁定关键代码。

(生产者的关键代码是它正在添加/尝试添加字符的位置)

(消费者的关键代码是它正在删除/尝试删除字符的位置)

互斥锁使得两个关键变量“头”和“尾”是稳定的 当任何一个进程都在访问循环队列时。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多