利用进程同步机制写出生产者消费者问题的源代码以及如何进行信号量的传递
时间: 2024-02-26 22:59:05 浏览: 93
下面是一个使用信号量来解决生产者消费者问题的简单示例代码:
```c++
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
// 生产者消费者问题
// 生产者不断往队列中添加数据,消费者不断从队列中取出数据进行处理
std::queue<int> g_queue; // 全局队列
std::mutex g_mutex; // 全局互斥锁,用于保护队列的访问
std::condition_variable g_cv; // 全局条件变量,用于唤醒等待的线程
const int g_max_queue_size = 10; // 队列的最大长度
void producer(int id)
{
while (true)
{
std::unique_lock<std::mutex> lock(g_mutex);
g_cv.wait(lock, []{ return g_queue.size() < g_max_queue_size; }); // 等待队列不满
int value = rand() % 100;
g_queue.push(value); // 添加数据
std::cout << "Producer " << id << " produced " << value << std::endl;
lock.unlock();
g_cv.notify_all(); // 唤醒等待的线程
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 生产者生产数据的时间间隔
}
}
void consumer(int id)
{
while (true)
{
std::unique_lock<std::mutex> lock(g_mutex);
g_cv.wait(lock, []{ return !g_queue.empty(); }); // 等待队列不空
int value = g_queue.front();
g_queue.pop(); // 取出数据
std::cout << "Consumer " << id << " consumed " << value << std::endl;
lock.unlock();
g_cv.notify_all(); // 唤醒等待的线程
std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 消费者处理数据的时间间隔
}
}
int main()
{
std::thread t1(producer, 1);
std::thread t2(consumer, 1);
std::thread t3(consumer, 2);
t1.join();
t2.join();
t3.join();
return 0;
}
```
在上述代码中,生产者和消费者线程都使用了互斥锁来保护队列的访问,并且使用条件变量来进行线程的等待和唤醒。在生产者向队列中添加数据时,如果队列已经满了,就会等待条件变量的通知;在消费者从队列中取出数据时,如果队列已经为空,也会等待条件变量的通知。
信号量是一种更加通用的同步机制,可以用来解决多种并发问题。在使用信号量时,需要先创建一个信号量对象,并指定初始值。在需要进行同步的地方,可以使用信号量的 wait() 和 signal() 方法来进行加锁和解锁操作。
下面是一段使用信号量来进行生产者消费者同步的示例代码:
```c++
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>
#include <semaphore.h>
// 生产者消费者问题
// 生产者不断往队列中添加数据,消费者不断从队列中取出数据进行处理
std::queue<int> g_queue; // 全局队列
std::mutex g_mutex; // 全局互斥锁,用于保护队列的访问
sem_t g_empty; // 空闲信号量,用于表示队列中空闲的空间数量
sem_t g_full; // 满载信号量,用于表示队列中已经占用的空间数量
const int g_max_queue_size = 10; // 队列的最大长度
void producer(int id)
{
while (true)
{
sem_wait(&g_empty); // 等待队列不满
std::unique_lock<std::mutex> lock(g_mutex);
int value = rand() % 100;
g_queue.push(value); // 添加数据
std::cout << "Producer " << id << " produced " << value << std::endl;
lock.unlock();
sem_post(&g_full); // 增加已占用空间数量,唤醒等待的线程
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 生产者生产数据的时间间隔
}
}
void consumer(int id)
{
while (true)
{
sem_wait(&g_full); // 等待队列不空
std::unique_lock<std::mutex> lock(g_mutex);
int value = g_queue.front();
g_queue.pop(); // 取出数据
std::cout << "Consumer " << id << " consumed " << value << std::endl;
lock.unlock();
sem_post(&g_empty); // 增加空闲空间数量,唤醒等待的线程
std::this_thread::sleep_for(std::chrono::milliseconds(2000)); // 消费者处理数据的时间间隔
}
}
int main()
{
sem_init(&g_empty, 0, g_max_queue_size); // 初始化空闲信号量,初始值为队列的最大长度
sem_init(&g_full, 0, 0); // 初始化满载信号量,初始值为0
std::thread t1(producer, 1);
std::thread t2(consumer, 1);
std::thread t3(consumer, 2);
t1.join();
t2.join();
t3.join();
sem_destroy(&g_empty); // 销毁信号量
sem_destroy(&g_full);
return 0;
}
```
在上述代码中,我们使用了 POSIX 标准库提供的信号量函数来创建和销毁信号量,并使用 sem_wait() 和 sem_post() 函数来进行加锁和解锁操作。在生产者向队列中添加数据时,如果队列已经满了,就会等待空闲信号量的通知;在消费者从队列中取出数据时,如果队列已经为空,也会等待满载信号量的通知。
阅读全文