进程同步-生产者消费者
时间: 2023-06-30 08:08:30 浏览: 75
生产者消费者问题是关于多线程或多进程同步的经典问题之一,通常用于解释如何正确地使用同步原语来避免数据竞争和死锁。
在生产者消费者问题中,有两个实体:生产者和消费者。生产者的职责是生产产品并将其放入缓冲区,而消费者的职责是从缓冲区中取出产品并消费它。缓冲区是一个有限的容器,可以容纳一定数量的产品。如果缓冲区已满,则生产者必须等待,直到有空间可用。如果缓冲区为空,则消费者必须等待,直到有产品可用。
为了避免竞争和死锁,我们需要使用同步原语来协调生产者和消费者的操作。其中一个常见的解决方案是使用信号量。我们可以使用两个信号量:一个表示缓冲区中可用的空间数量,另一个表示已经放置在缓冲区中的产品数量。当生产者放置一个产品时,它会递增第二个信号量,并递减第一个信号量。当消费者取出一个产品时,它会递减第二个信号量,并递增第一个信号量。如果缓冲区已满或已空,则相应的信号量将被阻塞,从而防止生产者或消费者继续操作。
下面是一个使用信号量解决生产者消费者问题的示例代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int in = 0;
int out = 0;
sem_t empty;
sem_t full;
pthread_mutex_t mutex;
void *producer(void *arg)
{
int item;
while (1) {
item = rand() % 100;
sem_wait(&empty);
pthread_mutex_lock(&mutex);
buffer[in] = item;
printf("Producer produced %d at index %d\n", item, in);
in = (in + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
pthread_exit(NULL);
}
void *consumer(void *arg)
{
int item;
while (1) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
item = buffer[out];
printf("Consumer consumed %d from index %d\n", item, out);
out = (out + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
pthread_exit(NULL);
}
int main()
{
pthread_t prod_tid;
pthread_t cons_tid;
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
pthread_create(&prod_tid, NULL, producer, NULL);
pthread_create(&cons_tid, NULL, consumer, NULL);
pthread_join(prod_tid, NULL);
pthread_join(cons_tid, NULL);
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
}
```
在这个示例中,我们有一个长度为10的缓冲区。生产者和消费者都是无限循环的线程函数。生产者随机生成一个整数,并将其放入缓冲区中。消费者从缓冲区中取出一个整数并将其打印到控制台中。注意到我们使用了两个信号量:empty和full,它们分别表示缓冲区中可用的空间数量和已经放置在缓冲区中的产品数量。我们还使用一个互斥锁来确保生产者和消费者的操作不会交叉进行。
在主函数中,我们初始化信号量和互斥锁,并创建两个线程:一个生产者和一个消费者。我们使用pthread_join函数等待线程完成并清理所有使用的资源。
这里提供的是一个基本的生产者消费者问题解决方案,还有其他的解决方案,例如使用条件变量或管程等。不同的解决方案适用于不同的场景,需要根据具体情况进行选择。