Operating system 二进制信号量和互斥量之间的区别

Operating system 二进制信号量和互斥量之间的区别,operating-system,mutex,semaphore,binary-semaphore,Operating System,Mutex,Semaphore,Binary Semaphore,二进制信号量和互斥量之间有什么区别吗?或者它们本质上是相同的吗? 只有获得互斥锁的线程才能释放互斥锁 二进制信号量可以由任何线程(或进程)发出 所以信号量更适合于一些同步问题,比如生产者-消费者 在Windows上,二进制信号量更像事件对象而不是互斥对象。 只有获得互斥锁的线程才能释放互斥锁 二进制信号量可以由任何线程(或进程)发出 所以信号量更适合于一些同步问题,比如生产者-消费者 在Windows上,二进制信号量更像事件对象而不是互斥对象。答案可能取决于目标操作系统。例如,我熟悉的至少一

二进制信号量和互斥量之间有什么区别吗?或者它们本质上是相同的吗?

  • 只有获得互斥锁的线程才能释放互斥锁
  • 二进制信号量可以由任何线程(或进程)发出
所以信号量更适合于一些同步问题,比如生产者-消费者

在Windows上,二进制信号量更像事件对象而不是互斥对象。

  • 只有获得互斥锁的线程才能释放互斥锁
  • 二进制信号量可以由任何线程(或进程)发出
所以信号量更适合于一些同步问题,比如生产者-消费者


在Windows上,二进制信号量更像事件对象而不是互斥对象。

答案可能取决于目标操作系统。例如,我熟悉的至少一个RTOS实现将允许对单个OS互斥体执行多个顺序“get”操作,只要它们都来自同一线程上下文。在允许另一个线程获取互斥锁之前,必须将多个get替换为相同数量的put。这与二进制信号量不同,二进制信号量一次只允许一个get,而不管线程上下文如何

这种互斥类型背后的思想是,通过一次只允许单个上下文修改数据来保护对象。即使线程获取互斥量,然后调用一个函数来进一步修改对象(并获取/放置保护器互斥量,使其围绕自己的操作),操作仍然应该是安全的,因为它们都发生在单个线程下

{
    mutexGet();  // Other threads can no longer get the mutex.

    // Make changes to the protected object.
    // ...

    objectModify();  // Also gets/puts the mutex.  Only allowed from this thread context.

    // Make more changes to the protected object.
    // ...

    mutexPut();  // Finally allows other threads to get the mutex.
}
当然,在使用此功能时,必须确保单个线程中的所有访问都是安全的


我不确定这种方法有多普遍,也不确定它是否适用于我熟悉的系统之外。有关这种互斥的示例,请参阅ThreadX RTO。

答案可能取决于目标操作系统。例如,我熟悉的至少一个RTOS实现将允许对单个OS互斥体执行多个顺序“get”操作,只要它们都来自同一线程上下文。在允许另一个线程获取互斥锁之前,必须将多个get替换为相同数量的put。这与二进制信号量不同,二进制信号量一次只允许一个get,而不管线程上下文如何

这种互斥类型背后的思想是,通过一次只允许单个上下文修改数据来保护对象。即使线程获取互斥量,然后调用一个函数来进一步修改对象(并获取/放置保护器互斥量,使其围绕自己的操作),操作仍然应该是安全的,因为它们都发生在单个线程下

{
    mutexGet();  // Other threads can no longer get the mutex.

    // Make changes to the protected object.
    // ...

    objectModify();  // Also gets/puts the mutex.  Only allowed from this thread context.

    // Make more changes to the protected object.
    // ...

    mutexPut();  // Finally allows other threads to get the mutex.
}
当然,在使用此功能时,必须确保单个线程中的所有访问都是安全的


我不确定这种方法有多普遍,也不确定它是否适用于我熟悉的系统之外。有关这种互斥的示例,请参阅ThreadX RTO。

它们不是同一件事。它们用于不同的目的
虽然这两种类型的信号量都有一个满/空状态,并且使用相同的API,但它们的用法非常不同

互斥信号量
互斥信号用于保护共享资源(数据结构、文件等)

互斥信号量由接收它的任务“拥有”。如果任务B尝试提供任务a当前持有的互斥锁,则任务B的调用将返回错误并失败

互斥锁始终使用以下顺序:

- SemTake - Critical Section - SemGive -塞姆塔克 -临界截面 -塞姆吉奇 下面是一个简单的例子:

Thread A Thread B Take Mutex access data ... Take Mutex <== Will block ... Give Mutex access data <== Unblocks ... Give Mutex 螺纹A螺纹B 接受互斥 访问数据
... 以互斥体为例,它们是不同的。它们用于不同的目的
虽然这两种类型的信号量都有一个满/空状态,并且使用相同的API,但它们的用法非常不同

互斥信号量
互斥信号用于保护共享资源(数据结构、文件等)

互斥信号量由接收它的任务“拥有”。如果任务B尝试提供任务a当前持有的互斥锁,则任务B的调用将返回错误并失败

互斥锁始终使用以下顺序:

- SemTake - Critical Section - SemGive -塞姆塔克 -临界截面 -塞姆吉奇 下面是一个简单的例子:

Thread A Thread B Take Mutex access data ... Take Mutex <== Will block ... Give Mutex access data <== Unblocks ... Give Mutex 螺纹A螺纹B 接受互斥 访问数据
... 以互斥对象为例,它们的同步语义非常不同:

  • 互斥锁允许序列化对给定资源的访问,即多个线程等待锁,一次一个,如前所述,线程拥有锁,直到锁完成:只有此特定线程可以解锁它
  • 二进制信号量是一个值为0和1的计数器:一个任务在它上面阻塞,直到any任务执行sem\u post。信号量通知资源可用,并提供等待机制,直到通知资源可用为止

因此,可以将互斥体视为从一个任务传递到另一个任务的令牌,将信号量视为交通红灯(它向某人发出可以继续的信号)。

它们的同步语义非常不同:

  • 互斥锁允许序列化对给定资源的访问,即多个线程等待锁,一次一个,如前所述,线程拥有锁,直到锁完成:只有此特定线程可以解锁它
  • 二进制信号量是一个值为0和1的计数器:一个任务阻塞它直到一个
    #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;
    }
    
    pthread_mutex_t mutex;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
    pthread_mutex_init (&mutex, &attr);
    
    if(pthread_mutex_unlock(&mutex)==EPERM)
     printf("Unlock failed:Mutex not owned by this thread\n");