📜  互斥与信号量

📅  最后修改于: 2021-05-20 06:42:44             🧑  作者: Mango

互斥锁和信号灯有什么区别?什么时候应该使用互斥锁,什么时候应该使用信号灯?

设计/开发智能应用程序需要对操作系统概念有具体的了解。我们的目标是教育读者这些概念,并向其他专家怪胎学习。

按照操作系统的术语,互斥量和信号量是提供同步服务(也称为同步原语)的内核资源。为什么我们需要这样的同步原语?不仅仅是一个就足够了吗?要回答这些问题,我们需要了解一些关键字。请阅读有关原子性和关键部分的文章。我们将通过示例进行说明,以更好地理解这些概念,而不是遵循通常的OS文本描述。

生产者-消费者问题:

注意,该内容是概括性的说明。实际细节会随实现方式而变化。

考虑标准的生产者-消费者问题。假设我们有一个4096字节长的缓冲区。生产者线程收集数据并将其写入缓冲区。使用者线程处理从缓冲区收集的数据。目的是两个线程不应同时运行。

使用Mutex:

互斥锁提供互斥,生产者或使用者都可以拥有密钥(互斥锁)并继续其工作。只要生产者填充了缓冲区,消费者就需要等待,反之亦然。

在任何时间点,只有一个线程可以使用整个缓冲区。可以使用信号量来概括该概念。

使用信号量:

信号量是广义互斥量。代替单个缓冲区,我们可以将4 KB缓冲区拆分为四个1 KB缓冲区(相同的资源)。信号量可以与这四个缓冲区关联。消费者和生产者可以同时在不同的缓冲区上工作。

误解:

二进制信号量互斥之间存在歧义。我们可能碰到互斥体是二进制信号量。但是事实并非如此!互斥量和信号量的目的是不同的。也许由于其实现方式的相似性,互斥体将被称为二进制信号量。

严格来说,互斥锁是一种锁定机制,用于同步对资源的访问。只有一个任务(可以是基于OS抽象的线程或进程)可以获取互斥量。这意味着存在与互斥锁关联的所有权,只有所有者才能释放锁(互斥锁)。

信号量是信号机制(“我做完了,您可以进行”这种信号)。例如,如果您正在手机上听歌(假定是一项任务),并且同时您的朋友打电话给您,则会触发一个中断,中断服务程序(ISR)会向该信号发出呼叫处理任务的信号,醒来。

一般的问题:

1.一个线程可以获取多个锁(Mutex)吗?

是的,一个线程可能需要多个资源,因此需要锁。如果没有可用的锁,则线程将在该锁上等待(阻止)。

2.互斥锁可以锁定多次吗?

互斥锁是一个锁。仅一个状态(锁定/解锁)与之关联。但是,递归互斥锁可以被锁定一次以上(符合POSIX的系统),其中一个计数与之关联,但仅保留一个状态(锁定/解锁)。程序员必须将互斥锁解锁的次数是其被锁定的次数。

3.如果非递归互斥体被多次锁定,会发生什么情况。

僵局。如果已经锁定了互斥锁的线程再次尝试锁定该互斥锁,它将进入该互斥锁的等待列表,这将导致死锁。这是因为没有其他线程可以解锁互斥锁。操作系统实现者可以谨慎识别互斥对象的所有者,如果互斥对象已被同一线程锁定,则返回该互斥对象以防止死锁。

4.二进制信号量和互斥量是否相同?

不。我们建议对它们进行单独处理,如信号与锁定机制中所述。但是二进制信号量可能会遇到与互斥锁相关的相同关键问题(例如,优先级倒置)。我们将在以后的文章中介绍这些内容。

程序员更喜欢使用互斥锁,而不是创建具有计数1的信号灯。

5.什么是互斥和关键部分?

某些操作系统在API中使用相同的单词关键部分。通常,互斥锁是一项昂贵的操作,这是由于与之相关的保护协议。最后,互斥的目标是原子访问。还有其他方法可以实现原子访问,例如禁用中断可能会更快,但会破坏响应能力。备用API使用了禁用中断。

6.什么是事件?

互斥量,信号量,事件,关键部分等的语义是相同的。所有都是同步原语。根据使用它们的成本,它们是不同的。我们应该查阅操作系统文档以获取确切的详细信息。

7.我们可以在中断服务程序中获取互斥/信号量吗?

一个ISR将在当前正在运行的线程的上下文中异步运行。不建议查询(阻塞调用)ISR中的同步原语的可用性。 ISR的含义很短,对互斥量/信号量的调用可能会阻止当前正在运行的线程。但是,ISR可以发信号通知信号或解锁互斥锁。

8.当互斥量/信号量不可用时,我们所说的“线程阻塞”是什么意思?

每个同步原语都有一个与其关联的等待列表。当资源不可用时,请求线程将从处理器的运行列表移至同步原语的等待列表。当资源可用时,等待列表中优先级较高的线程将获取资源(更确切地说,这取决于调度策略)。

9.当资源不可用时,线程是否必须始终阻塞?

没必要。如果设计确定“当资源不可用时必须做什么”,则线程可以承担这项工作(一个不同的代码分支)。为了支持应用程序要求,操作系统提供了非阻塞API。

例如POSIX pthread_mutex_trylock()API。当互斥锁不可用时,函数将立即返回,而API pthread_mutex_lock()会阻塞线程,直到资源可用为止。

参考:

http://www.netrino.com/node/202

http://doc.trolltech.com/4.7/qsemaphore.html

还要将互斥量/信号量与Peterson算法和Dekker算法进行比较。一个很好的参考书是《并发艺术》一书。还可以在Qt文档中探讨读取器锁和写入器锁。

锻炼:

实现一个程序,在同一会话中执行多次时,该程序将打印一条消息“实例正在运行”。例如,如果我们在Windows中观察Word应用程序或Adobe Reader,则在任务管理器中只能看到一个实例。如何执行呢?