同步与互斥:互斥锁、条件变量、信号量的联系与区别

您所在的位置:网站首页 c语言锁的使用 同步与互斥:互斥锁、条件变量、信号量的联系与区别

同步与互斥:互斥锁、条件变量、信号量的联系与区别

2023-05-27 01:33| 来源: 网络整理| 查看: 265

概念

互斥(Mutex) :互斥是一种保证多线程或多进程在访问共享资源时不会发生冲突的技术。

同步(Synchronization) :同步通常涉及多个线程或进程之间的协调,以保证它们以特定的顺序执行某些操作。

啰嗦一句,初学计算机时,我一直不太明白“资源”是什么意思?是指内存?硬盘?——是的,内存、硬盘都是资源,但是在程序中,可以把资源理解为“变量”。一块内存就是用一个变量来表示,例如C中的指针;一个文件也是用一个变量(文件描述符)来表示。变量可以表示购票软件中的火车票,支付宝中的余额等等,而这些都可以称之为资源。

从概念上看两者是不一样的,但互斥可以被看作是一种特定的同步形式,即在同一时间只允许一个线程访问特定的代码段(临界区)。所以不必刻意从概念上进行区分,而是从实际情况中进行区分。即每次只允许一个线程/进程进行操作的就是互斥,其余都是同步。

互斥锁、条件变量、信号量的联系与区别

互斥锁(Mutex)、条件变量(Condition Variables)和信号量(Semaphores)都是在并发编程中用于同步和协调多线程或多进程的技术。虽然Mutex的名字是互斥锁,但有时也可以用于同步。再次印证前面所说,不必刻意区分。

先看一下概念:

互斥锁(Mutex) :互斥锁主要用于保护共享资源,避免同时被多个线程或进程修改。当一个线程获得互斥锁后,其他线程必须等待直到该线程释放锁。互斥锁是最简单的一种同步机制,主要用于实现"临界区"的概念。

条件变量(Condition Variables) :条件变量主要用于线程间的同步。它们通常与互斥锁一起使用(后面会解释)。线程在某些条件下等待,并在条件满足时被唤醒。例如,一个线程可能在等待队列中有元素可处理时才继续运行。如果条件不满足,线程将会被阻塞,并释放已持有的互斥锁,当条件满足(通常由其他线程触发)时,线程将被唤醒并重新获取互斥锁。

信号量(Semaphores) :信号量是一种更复杂的同步机制,可以被视为能够持有多个 "许可" 的互斥锁。信号量有两个主要的操作:wait(或称 P 操作)和 post(或称 V 操作)。wait 操作会获取一个许可,如果许可不可用,则线程将阻塞直到许可可用。post 操作会释放一个许可。信号量可以用来控制同时访问某个资源的线程数。

互斥硕可以看做是一种特殊的信号量,即只有0/1两种状态,只有为1时才能加锁成功。

一个例子

可通过力扣题目来练习信号量、互斥锁、条件变量的使用1115. 交替打印 FooBar (考研的同学一定要练习一下)

c++中的互斥锁、条件变量和信号量

具体可参考c++并发支持库

//互斥锁 std::mutex //条件变量 std::condition_variable //计数信号量 std::counting_semaphore(c++20) //二值信号量——相当于互斥锁 std::binary_semaphore(c++20) //常用互斥锁管理类 std::lock_guard //实现严格基于作用域的互斥体所有权包装器 std::unique_lock //实现可移动的互斥体所有权包装器

通常不直接使用 std::mutex。而是通过std::unique_lock 、 std::lock_guard 的方式管理互斥锁。 std::unique_lock,std::lock_guard,以及std::scoped_lock(C++17以后)都是互斥锁(mutex)的RAII封装。RAII(Resource Acquisition Is Initialization)是一种在 C++ 中管理资源的编程技术,其目标是将资源的生命周期与对象的生命周期捆绑在一起,以确保在任何情况下(包括错误和异常)资源的正确释放。

相比于直接使用 std::mutex,使用这些封装有以下好处:

异常安全:如果在互斥锁锁定之后、解锁之前的代码中抛出异常,那么互斥锁就可能永远不会被解锁,导致死锁。然而,如果我们使用的是 std::unique_lock 或者 std::lock_guard,当它们的对象超出作用域时,它们的析构函数将自动解锁互斥锁,从而避免死锁。(关键) 代码简洁:无需在所有可能退出函数的地方明确调用 unlock()。当 std::unique_lock 或者 std::lock_guard 的对象超出作用域时,它们的析构函数将自动解锁互斥锁。

所以std::condition_variable提供的接口void wait( std::unique_lock& lock );要求传入一个std::unique_lock而不是std::mutex。如此保证了异常安全。

Linux平台下的互斥锁、条件变量和信号量 //信号量接口定义 #include //初始化信号量 //pshared:该信号量在线程间共享还是进程间共享,0表示线程共享,1表示进程共享 //value:信号量的初始值 int sem_init(sem_t *sem, int pshared, unsigned int value); //销毁信号量 int sem_destroy(sem_t *sem); //P操作,如果sem


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3