Lock vs Semaphore vs Condition Variable vs Monitor(中文)

目录

1. Critical Section(CS)

2. Lock

3. Semaphore

4. Condition variable

5. Monitor

6. 总结


在多线程(并发)程序中,多个线程会访问同一个共享内存,为了避免产生一些奇怪的结果,这些线程应该按照合适的顺序访问共享内存,这个过程称为同步(synchronization)。可是仅仅保持同步还不够,为了让同步更加高效,多个线程互相之间也要保持交流。这篇文章主要讨论线程同步(synchronization)和交流(communication)。

1. Critical Section(CS)

临界区(Critical section)是程序的一段代码块,临界区不能被多个线程在同一时间访问,临界区的访问是互斥的,某一时刻最多只能有一个线程能进临界区。

2. Lock

Lock,叫做锁,提供了一种互斥的方式,Lock能保证某一时刻只有一个线程能进入到临界区(CS),如下面的伪代码:

Lock num_mutex; // num_mutex 是一个Lock对象
 
######################################
 
 
Thread1:
 
// 获取锁
mutex_lock(&num_mutex);
 
// ******** 临界区 *******
num++;
// ******** 临界区 *******
 
// 释放锁
mutex_unlock(&num_mutex); 
 
 
######################################
 
 
Thread2:
 
// 获取锁
mutex_lock(&num_mutex);
 
// ******** 临界区 *******
num++;
// ******** 临界区 *******
 
// 释放锁
mutex_unlock(&num_mutex);

在上面的伪代码中,num++ 不是原子性操作,所以 num++ 不能同时被两个线程执行。 当Thread1和Thread2同时获取锁,只有一个线程最终能获取锁,然后获取到锁的线程进入临界区(执行num++),另一个线程必须一直等待到锁被释放。

再来看下经典的生产者-消费者问题,用Lock可以解决这个问题,如下代码:

Lock count_mutex; // count_mutex 是一个Lock对象

int count = 0; // 待消费的商品数量
 
 
#############################################
 
 
 
Producer Thread
 
// 获取锁
mutex_lock(&count_mutex);
 
// 如果count等于 MAX_SIZE, 不能生产,需要等待
while(count == MAX_SIZE){
    
    // 释放锁,将锁让给Consumer
    mutex_unlock(&count_mutex);
 
    Thread.sleep(3000); // 睡眠3秒
    
    // 睡眠唤醒之后,再次获取锁
    mutex_lock(&count_mutex);
}
 
// ***** 临界区 ****//
 
// 生产
produce();
 
// 生产之后,count加1
count++;
 
// ***** 临界区 ****//
 
// 生产之后释放锁
mutex_unlock(&count_mutex);
 
 
 
##############################################
 
 
Consumer Thread
 
// 获取锁
mutex_lock(&count_mutex);
 
// 如果count 等
哲学家就餐问题的设计与实现。 【问题描述】+ 哲学家进餐问题是操作系统中经典的同步问题,由 Di ikstza提出。五位哲学家围坐圆 桌,每人面前有一盘面,左右各有一把共享叉子。哲学家交替进行思考进餐:进餐需后时 拿起左右两把又子。问题在于并发执行时,可能所有哲学家同时掌起左叉,等待右叉,导致 死锁一 一所有进程阻塞,无法推进。这模拟了多进程竞争有限资源(如工/0设备)时的冲突, 需设计机制避免僵局。 【设计要求】+ 避免死锁,确保系统安全; 防止饥饿,保证所有哲学家最终能进餐; 支持并发性,允许多个哲宁家同时进餐以提高效率;。 并实现公平性,避免某些哲学家长期等待。 设计应简单高效,减少额外开销,且易于扩展。 常见约束包括:哲学家必须原子性地获取两把又子,资源(叉子〉不可抢占,进程行为 非确定性。 『数据结构】+ 王要使用信号量(semaphore)管理资源:每个叉子对应一个二元信号量(初始值 1), 表示可用性(如 semaphore fork[5] =(1,1,1,1,1))。哲学家进程通过 rait (forkGJ) signal (fork[了)操作获取释放叉子。辅助结构包括互斥锁(mutez)用于保护临界区(如 限制同时尝试进餐的哲学家数),或整型数组跟踪又子状态。更高级方案可能引入管程 (monitor)封装操作。。 【分折与实现】。 分析:死锁风险源于循环等待(所有哲学家持有一叉等待另一叉)。解决震破坏死锁条 件,如引入资源有序获取《强制哲学家先拿编号较小叉子〉或限制并发数(如只允许多至4 人同时尝试〉。实现时,用信号量构建算法:例如,设蛋一个互斥信号量控制进餐人数,哲 学家按顺序申请叉子。代码中每个哲学家进程循环执行:思考、申请叉子《有序 rait)、进 餐、程放买子(signal)。此方案确保安全性、活跃性公平性,时间复杂度0(1) per 操作。c++
06-17
### 哲学家就餐问题的C++实现 哲学家就餐问题是一个经典的并发控制问题,涉及信号量、互斥锁以及死锁避免机制。以下是基于C++的实现示例,包含信号量、互斥锁死锁避免机制[^1]。 #### 代码实现 ```cpp #include <iostream> #include <thread> #include <vector> #include <mutex> #include <condition_variable> #include <chrono> const int NUM_PHILOSOPHERS = 5; // 每个哲学家对应的筷子 std::mutex forks[NUM_PHILOSOPHERS]; // 条件变量用于协调哲学家的行为 std::condition_variable cv; std::mutex cv_mutex; bool eating[NUM_PHILOSOPHERS] = {false}; void philosopher(int id) { while (true) { // 思考 std::cout << "Philosopher " << id << " is thinking." << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 尝试获取左侧筷子 int left_fork = id; int right_fork = (id + 1) % NUM_PHILOSOPHERS; std::unique_lock<std::mutex> lock(cv_mutex); cv.wait(lock, [id]() { return !eating[left_fork] && !eating[right_fork]; }); // 获取左侧筷子 forks[left_fork].lock(); eating[left_fork] = true; // 获取右侧筷子 forks[right_fork].lock(); eating[right_fork] = true; // 吃饭 std::cout << "Philosopher " << id << " is eating." << std::endl; std::this_thread::sleep_for(std::chrono::milliseconds(200)); // 放下筷子 forks[left_fork].unlock(); forks[right_fork].unlock(); eating[left_fork] = false; eating[right_fork] = false; cv.notify_all(); } } int main() { std::vector<std::thread> philosophers; for (int i = 0; i < NUM_PHILOSOPHERS; ++i) { philosophers.emplace_back(philosopher, i); } for (auto& t : philosophers) { t.join(); } return 0; } ``` #### 代码解析 1. **信号量与互斥锁**:每个哲学家对应一对筷子(`forks`),通过互斥锁来模拟筷子的占用状态[^2]。 2. **条件变量**:使用条件变量 `cv` 互斥锁 `cv_mutex` 来确保哲学家在尝试获取筷子时不会发生死锁。只有当左右筷子均未被占用时,哲学家才能开始吃饭[^3]。 3. **死锁避免**:通过条件变量的等待机制,确保哲学家不会同时持有两把筷子而陷入死锁状态。此外,通过按顺序获取筷子(先左后右)进一步降低死锁的可能性。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值