二进制信号量和互斥量之间有区别吗?或者它们本质上是相同的?
当前回答
在Windows上,互斥量和二进制信号量之间有两个区别:
互斥锁只能由拥有所有权的线程释放,即之前调用Wait函数的线程(或在创建互斥锁时获得所有权的线程)。任何线程都可以释放信号量。 线程可以在互斥锁上重复调用等待函数而不会阻塞。但是,如果你在一个二进制信号量上调用了两次等待函数,而中间没有释放信号量,线程就会阻塞。
其他回答
二进制信号量和互斥量的区别: 所有权: 信号量甚至可以从非当前所有者发出信号(发布)。这意味着您可以简单地从任何其他线程发布,尽管您不是所有者。
信号量是进程中的公共属性,它可以简单地由非所有者线程发布。 请用粗体字标出这个区别,这意味着很多。
最好的解决方案
唯一的区别是
1.互斥锁-> lock和unlock属于锁定互斥锁的线程。
2.信号量->没有所有权,即;如果一个线程调用semwait(s),任何其他线程都可以调用sempost(s)来移除锁。
在看了上面的帖子后,这个概念对我来说很清楚。但仍有一些挥之不去的问题。所以,我写了一小段代码。
当我们试图给出一个信号量而不接收它时,它就会通过。但是,当你试图给出一个互斥量而不获取它时,它会失败。我在Windows平台上进行了测试。启用USE_MUTEX使用MUTEX运行相同的代码。
#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1
DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );
HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;
int main(void)
{
#ifdef USE_MUTEX
ghMutex = CreateMutex( NULL, FALSE, NULL);
if (ghMutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
#else
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
if (ghSemaphore == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
#endif
// Create thread 1.
Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);
if ( Handle_Of_Thread_1 == NULL)
{
printf("Create first thread problem \n");
return 1;
}
/* sleep for 5 seconds **/
Sleep(5 * 1000);
/*Create thread 2 */
Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);
if ( Handle_Of_Thread_2 == NULL)
{
printf("Create second thread problem \n");
return 1;
}
// Sleep for 20 seconds
Sleep(20 * 1000);
printf("Out of the program \n");
return 0;
}
int my_critical_section_code(HANDLE thread_handle)
{
#ifdef USE_MUTEX
if(thread_handle == Handle_Of_Thread_1)
{
/* get the lock */
WaitForSingleObject(ghMutex, INFINITE);
printf("Thread 1 holding the mutex \n");
}
#else
/* get the semaphore */
if(thread_handle == Handle_Of_Thread_1)
{
WaitForSingleObject(ghSemaphore, INFINITE);
printf("Thread 1 holding semaphore \n");
}
#endif
if(thread_handle == Handle_Of_Thread_1)
{
/* sleep for 10 seconds */
Sleep(10 * 1000);
#ifdef USE_MUTEX
printf("Thread 1 about to release mutex \n");
#else
printf("Thread 1 about to release semaphore \n");
#endif
}
else
{
/* sleep for 3 secconds */
Sleep(3 * 1000);
}
#ifdef USE_MUTEX
/* release the lock*/
if(!ReleaseMutex(ghMutex))
{
printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
}
#else
if (!ReleaseSemaphore(ghSemaphore,1,NULL) )
{
printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
}
#endif
return 0;
}
DWORD WINAPI Thread_no_1( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_1);
return 0;
}
DWORD WINAPI Thread_no_2( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_2);
return 0;
}
信号量允许您发出“使用资源完成”的信号,即使它从未拥有该资源,这一事实使我认为在信号量的情况下,拥有和发出信号之间存在非常松散的耦合。
在理论层面上,它们在语义上并无不同。您可以使用信号量实现互斥量,反之亦然(参见这里的示例)。在实践中,实现是不同的,它们提供的服务也略有不同。
实际的区别(就围绕它们的系统服务而言)在于互斥锁的实现旨在成为一种更轻量级的同步机制。在oracle语言中,互斥锁被称为锁存器,而信号量被称为等待。
在最低级别,他们使用某种原子测试和设置机制。它读取内存位置的当前值,计算某种条件,并在一条不能中断的指令中写入该位置的值。这意味着您可以获得一个互斥锁,并测试是否有人在您之前拥有它。
典型的互斥量实现有一个进程或线程执行test-and-set指令,并评估是否有其他东西设置了互斥量。这里的关键点是与调度程序没有交互,因此我们不知道(也不关心)谁设置了锁。然后,我们要么放弃我们的时间片,并在任务重新调度时再次尝试它,要么执行自旋锁。自旋锁是这样一种算法:
Count down from 5000:
i. Execute the test-and-set instruction
ii. If the mutex is clear, we have acquired it in the previous instruction
so we can exit the loop
iii. When we get to zero, give up our time slice.
当我们完成执行受保护的代码(称为临界区)时,我们只需将互斥量的值设置为零或其他表示“清除”的值。如果有多个任务试图获取互斥量,那么下一个计划在互斥量释放后的任务将获得对资源的访问权。通常情况下,您可以使用互斥来控制同步资源,在这种资源中,只需要在很短的时间内对其进行独占访问,通常是对共享数据结构进行更新。
A semaphore is a synchronised data structure (typically using a mutex) that has a count and some system call wrappers that interact with the scheduler in a bit more depth than the mutex libraries would. Semaphores are incremented and decremented and used to block tasks until something else is ready. See Producer/Consumer Problem for a simple example of this. Semaphores are initialised to some value - a binary semaphore is just a special case where the semaphore is initialised to 1. Posting to a semaphore has the effect of waking up a waiting process.
一个基本的信号量算法如下所示:
(somewhere in the program startup)
Initialise the semaphore to its start-up value.
Acquiring a semaphore
i. (synchronised) Attempt to decrement the semaphore value
ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.
Posting a semaphore
i. (synchronised) Increment the semaphore value
ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.
iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.
在二进制信号量的情况下,两者之间的主要实际区别是围绕实际数据结构的系统服务的性质。
编辑:正如evan正确地指出的那样,自旋锁会降低单个处理器的速度。你只能在多处理器上使用自旋锁,因为在单处理器上,持有互斥锁的进程永远不会在另一个任务运行时重置它。自旋锁只在多处理器架构上有用。
互斥量是任何想要解决临界区问题的算法都必须遵循的标准,而二进制信号量本身是一个可以取0和1值的变量。
推荐文章
- 如何检查Python的操作系统?
- 在Swift中,什么相当于Objective-C的“@synchronized”?
- 信号量和监视器——有什么不同?
- 如何使用JavaScript找到操作系统的详细信息?
- 我如何检查操作系统与预处理器指令?
- 如何在没有操作系统的情况下运行程序?
- 线程之间共享哪些资源?
- Windows、Mac OS X和Linux是用什么语言编写的?
- 什么时候应该使用自旋锁而不是互斥锁?
- context . start前台服务()没有调用service . start前台()
- 在c#中使用全局互斥锁的好模式是什么?
- 什么是信号量?
- 什么是私有字节、虚拟字节、工作集?
- 用简单的术语解释什么是文件描述符?
- 开始操作系统开发有哪些资源?