#include <iostream> #include <thread> #include <mutex> #include <condition_variable> using namespace std; const int N = 5; // 哲学家数量 mutex forks[N]; // 叉子互斥锁 condition_variable cv[N]; // 条件变量,用于线程同步 void philosopher(int i) { while (true) { // 模拟思考 cout << "Philosopher " << i << " is hungry." << endl; // 拿起左手的叉子 forks[i].lock(); cout << "Philosopher " << i << " picks up left fork." << endl; // 尝试拿起右手的叉子 unique_lock<mutex> lock(forks[(i + 1) % N], defer_lock); while (!lock.try_lock()) { cv[i].wait(lock); } cout << "Philosopher " << i << " picks up right fork." << endl; // 进餐 cout << "Philosopher " << i << " starts eating." << endl; this_thread::sleep_for(chrono::milliseconds(rand() % 1000)); cout << "Philosopher " << i << " finishes eating." << endl; // 放下右手的叉子 lock.unlock(); cv[(i + 1) % N].notify_one(); cout << "Philosopher " << i << " puts down right fork." << endl; // 放下左手的叉子 forks[i].unlock(); cout << "Philosopher " << i << " puts down left fork." << endl; } } int main() { thread philosophers[N]; for (int i = 0; i < N; i++) { philosophers[i] = thread(philosopher, i); } for (int i = 0; i < N; i++) { philosophers[i].join(); } return 0; }分析案例
时间: 2024-01-06 17:07:11 浏览: 133
这是一个经典的哲学家就餐问题,使用了互斥锁和条件变量来实现线程同步。
在哲学家就餐问题中,有5个哲学家围坐在一张圆桌前,每个哲学家面前都有一只叉子。哲学家只有在同时拿到左右两只叉子时才能进餐,进餐完毕后需要放下叉子。
在代码实现中,每个哲学家对应一个线程,线程函数philosopher(i)模拟了哲学家的行为。当哲学家饥饿时,首先尝试拿起左手的叉子,如果成功则继续尝试拿起右手的叉子,如果失败则等待。当哲学家成功拿起左右两只叉子时,进餐一段时间后放下叉子,释放右手的叉子,并通知右边的哲学家可以拿起叉子了。
通过互斥锁保证了同一时刻只能有一个哲学家拿起同一只叉子,通过条件变量实现线程间的等待和通知,以避免死锁和忙等待的问题。
该实现方式在一定程度上解决了哲学家就餐问题,但仍存在一些问题,例如可能会出现饥饿死锁等问题。在实际应用中,需要根据具体情况进行进一步的优化和改进。
相关问题
Windows环境下创建一个控制台进程,创建n个线程模拟生产者和消费者,实现进程(线程)的同步与互斥
这是一个典型的生产者消费者问题,可以使用互斥锁和条件变量来实现同步和互斥。
下面是一个简单的示例代码,使用互斥锁和条件变量来实现生产者消费者问题的同步和互斥:
```c++
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
using namespace std;
mutex mtx;
condition_variable cv;
queue<int> q;
const int n = 10; // 缓冲区大小
int count = 0; // 生产者和消费者的数量
// 生产者线程
void producer(int id) {
while (count < n) {
// 生产数据
int data = rand() % 100;
// 加锁
unique_lock<mutex> lck(mtx);
while (q.size() >= n) {
// 缓冲区已满,等待消费者消费
cv.wait(lck);
}
// 将数据加入缓冲区
q.push(data);
cout << "Producer " << id << " produced " << data << endl;
// 唤醒消费者
cv.notify_all();
// 解锁
lck.unlock();
// 生产者数量加1
count++;
}
}
// 消费者线程
void consumer(int id) {
while (count < n) {
// 加锁
unique_lock<mutex> lck(mtx);
while (q.empty()) {
// 缓冲区为空,等待生产者生产
cv.wait(lck);
}
// 从缓冲区取出数据
int data = q.front();
q.pop();
cout << "Consumer " << id << " consumed " << data << endl;
// 唤醒生产者
cv.notify_all();
// 解锁
lck.unlock();
// 消费者数量加1
count++;
}
}
int main() {
// 创建生产者线程和消费者线程
thread t1(producer, 1);
thread t2(consumer, 1);
thread t3(producer, 2);
thread t4(consumer, 2);
// 等待线程执行完毕
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
```
上面的代码创建了两个生产者线程和两个消费者线程,它们共享一个缓冲区。生产者线程会不断地生产数据并将数据加入缓冲区,直到生产者数量达到n。消费者线程会不断地从缓冲区取出数据并消费,直到消费者数量达到n。在生产者和消费者之间使用互斥锁和条件变量来保证同步和互斥,确保生产者和消费者之间的正确性。
银行有n个柜员负责为顾客服务,顾客进入银行先取一个号码,然后等着叫号。当某个柜员空闲下来,就叫下一个号。 编程实现该问题,用P、V操作实现柜员和顾客的同步。使用C语言或C++语言
以下是一个简单的使用P、V操作实现柜员和顾客同步的C++代码:
```c++
#include <iostream>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
// 柜员数量
const int kNumTellers = 3;
// 等待的顾客队列
queue<int> customer_queue;
// 顾客队列的互斥量和条件变量
mutex customer_queue_mutex;
condition_variable customer_queue_cv;
// 柜员的互斥量和条件变量
mutex teller_mutex[kNumTellers];
condition_variable teller_cv[kNumTellers];
// 柜员状态,0代表空闲,1代表忙碌
int teller_state[kNumTellers] = {0};
// 取号函数
int take_number()
{
static int number = 0;
return ++number;
}
// 顾客线程函数
void customer_thread(int id)
{
int number = take_number();
// 将号码放入队列中
unique_lock<mutex> lock(customer_queue_mutex);
customer_queue.push(number);
cout << "Customer " << id << " takes number " << number << endl;
lock.unlock();
customer_queue_cv.notify_one();
// 等待柜员叫号
int teller_id = -1;
unique_lock<mutex> teller_lock;
while (teller_id == -1)
{
teller_lock.lock();
for (int i = 0; i < kNumTellers; i++)
{
if (teller_state[i] == 0)
{
teller_id = i;
teller_state[i] = 1;
break;
}
}
if (teller_id == -1)
{
teller_lock.unlock();
this_thread::yield();
}
}
cout << "Customer " << id << " is served by teller " << teller_id << endl;
teller_cv[teller_id].notify_one();
teller_lock.unlock();
}
// 柜员线程函数
void teller_thread(int id)
{
while (true)
{
// 等待顾客
unique_lock<mutex> lock(customer_queue_mutex);
customer_queue_cv.wait(lock, [](){ return !customer_queue.empty(); });
// 取出一个顾客
int customer_id = customer_queue.front();
customer_queue.pop();
lock.unlock();
// 等待柜员空闲
unique_lock<mutex> teller_lock(teller_mutex[id]);
teller_cv[id].wait(teller_lock, [&](){ return teller_state[id] == 1; });
teller_state[id] = 0;
teller_lock.unlock();
// 为顾客服务
cout << "Teller " << id << " serves customer " << customer_id << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
int main()
{
// 创建柜员线程
thread teller_threads[kNumTellers];
for (int i = 0; i < kNumTellers; i++)
{
teller_threads[i] = thread(teller_thread, i);
}
// 创建顾客线程
const int kNumCustomers = 10;
thread customer_threads[kNumCustomers];
for (int i = 0; i < kNumCustomers; i++)
{
customer_threads[i] = thread(customer_thread, i);
this_thread::sleep_for(chrono::milliseconds(100));
}
// 等待顾客线程结束
for (int i = 0; i < kNumCustomers; i++)
{
customer_threads[i].join();
}
// 通知柜员线程结束
for (int i = 0; i < kNumTellers; i++)
{
teller_cv[i].notify_one();
}
// 等待柜员线程结束
for (int i = 0; i < kNumTellers; i++)
{
teller_threads[i].join();
}
return 0;
}
```
该程序中,顾客线程通过取号后将自己的号码放入等待队列中,然后等待柜员叫号。柜员线程则不断从等待队列中取出顾客,然后等待自己空闲后为顾客服务。在程序中,我们使用了互斥量和条件变量来实现线程之间的同步。
阅读全文