互斥锁、信号量和自旋锁的区别

31

我正在进行与IPC相关的实验,特别是Mutex、Semaphore和Spin Lock。

我学到的是,Mutex用于异步锁定(根据我在网上读到的理论),是伴随着休眠机制的;Semaphore是同步锁定(伴随着信号和休眠)机制;而Spin Locks是同步但非休眠机制。

有没有人能帮我深入澄清这些问题?还有另一个疑问是关于Mutex,当我用线程和Mutex编写程序时,当一个线程正在运行时,另一个线程不处于休眠状态,而是不断尝试获取锁。这样,Mutex是休眠还是非休眠的?


我认为你可能也想阅读这篇文章。https://dev59.com/h2025IYBdhLWcg3wqn4N - Ritesh
3个回答

68

首先,需要记住这些“同步对象”的目标:

这些对象旨在为同一进程或不同进程中的多个线程之间提供高效且协调一致的共享数据的使用。

这些对象可以被“获取”“释放”

就是这样了!!!故事结束了!!!

现在,如果有帮助的话,让我加点料:

1) 临界区(Critical Section)= 用户对象,用于允许来自许多其他线程的一个活动线程(在同一进程内)执行,其它未被选择的线程(@获取此对象)则被置于睡眠状态

[没有进程间能力,非常原始的对象]。

2) 互斥量信号量(Mutex Semaphore,又称Mutex)= 内核对象,用于允许来自许多其他线程的一个活动线程(在同一进程内或在不同进程之间)执行,其它未被选择的线程(@获取此对象)则被置于睡眠状态。该对象支持线程所有权、线程终止通知、递归(同一线程的多个“获取”调用)和“优先级反转避免”。

[进程间能力,使用非常安全,是一种“高级”的同步对象]。

3) 计数信号量(也称为信号量) = 内核对象,用于允许在同一进程或不同进程中的许多其他活动线程组中执行线程组。 其他未被选中的线程(在获取此对象时)将被置于休眠状态。

[然而,跨进程的能力不太安全,因为它缺少以下“互斥”属性:线程终止通知,递归?,“优先级反转避免”?等等]。

4) 现在,谈论“自旋锁”,首先是一些定义:

关键区域 = 2个或多个进程共享的内存区域。

锁定 = 值允许或拒绝进入“关键区域”的变量。 (它可以实现为简单的“布尔标志”)。

忙等待 = 不断测试变量,直到出现某个值。

最终:

自旋锁(也称为自旋锁) = 使用忙等待锁定。 (通过xchg或类似的原子操作获得锁定)。

[没有线程睡眠,通常仅在内核级别使用。 对于用户级代码效率低下]。

最后一点评论,我不确定,但我可以打赌上面的前三个同步对象(#1,#2和#3)将其作为实现的一部分使用该简单的机制(#4)。

祝您有美好的一天!

参考文献:

-《嵌入式系统实时概念》著者:Qing Li, Caroline Yao(CMP Books)。

-《现代操作系统》第3版作者:Andrew Tanenbaum(Pearson Education International)。

-《为Microsoft Windows编写应用程序》第4版著者:Jeffrey Richter(Microsoft Programming Series)。


关于“临界区……其他线程被置于睡眠状态”的说法,这只适用于非常原始的临界区实现,在进入该区域时禁用中断。请参阅Wikipedia-临界区以讨论该实现,以及使用信号量进行更有效实现的替代方案,仍然称为代码的“临界区”。 - ToolmakerSteve
2
在这里稍后的定义更加误导人,因为它们说“其他线程被置于睡眠状态”。这让我觉得其他线程根本无法运行,这完全忽略了这些机制的要点。具体来说,任何需要使用共享资源(由这些机制之一保护)的线程确实必须被阻塞(置于睡眠状态),但是不使用共享资源的线程不会被置于睡眠状态 - ToolmakerSteve
互斥锁和信号量之间的区别是比较微弱的(不知道这是否与参考文献有关,还是与本答案的重新陈述有关)。要更清楚地区分,请参见https://barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore。其中关键句子是:“正确使用信号量是为了从一个任务向另一个任务发出信号。互斥锁则是由每个使用它所保护的共享资源的任务按顺序获取和释放。相比之下,使用信号量的任务要么发出信号,要么等待,而不是两者兼备。” - ToolmakerSteve
抱歉过多强调互斥锁/信号量的区别。在许多,也许是大多数的讨论中,信号量具有计数>1的能力是被强调的。然后书籍/文章/stackoverflow帖子将会有一个计数>1的信号量示例。继续危险地滥用信号量。并掩盖了更有用的区别,即信号量类似于可以传递的令牌或棒。 - ToolmakerSteve
@ToolmakerSteve,与此同时,由于其较高的优先级,tSignalTask()可能会再次运行多次。但是,正如您所看到的,如果在处理每个数据包之前调用'acquire(CS1)或wait(CS1)',则tWaitTask()永远不会“错过”任何“数据包”。//这本书还提到了另一种情况(多个共享资源访问同步),它适合这个对象,但我不确定。原因?这就是Barr在上面提供的参考文献中提到的。将会有一个问题,即从已经拥有令牌的资源中访问哪个资源。 - fante
显示剩余9条评论

3

这里有一个关于信号量和互斥锁之间区别的很好的解释:

http://blog.feabhas.com/2009/09/mutex-vs-semaphores-–-part-1-semaphores/

简单来说,至少对于二进制信号量来说,它与所有权有关,但我建议您阅读整篇文章。


1
另一个有趣的帖子:https://dev59.com/h2025IYBdhLWcg3wqn4N - Ritesh

0

互斥锁是锁定机制,而信号量是等待和信号机制。两者有不同的应用。

印度科学院教授给出了非常好的解释。

视频链接


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接