Разница между двоичным семафором и мьютексом - PullRequest
744 голосов
/ 15 сентября 2008

Есть ли разница между двоичным семафором и мьютексом или они по сути одинаковы?

Ответы [ 30 ]

4 голосов
/ 13 августа 2013

Концепция была понятна мне после перехода выше постов. Но были некоторые затяжные вопросы. Итак, я написал этот маленький кусочек кода.

Когда мы пытаемся дать семафор, не беря его, он проходит. Но когда вы пытаетесь дать мьютекс, не беря его, это не получается. Я проверил это на платформе 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;
}
4 голосов
/ 23 февраля 2012

В Windows разница, как показано ниже. MUTEX: процесс, который успешно выполняет wait , должен выполнить сигнал и наоборот. ДВОЙНЫЕ СЕМАФОРЫ: Различные процессы могут выполнять ожидание или сигнал операцию с семафором.

3 голосов
/ 15 июля 2016

В то время как двоичный семафор может использоваться как мьютекс, мьютекс является более конкретным вариантом использования, так как только процесс, который заблокировал мьютекс, должен его разблокировать. Это ограничение собственности позволяет обеспечить защиту от:

  • Случайный выпуск
  • Рекурсивный тупик
  • Task Death Deadlock

Эти ограничения не всегда присутствуют, потому что они снижают скорость. Во время разработки вашего кода вы можете временно включить эти проверки.

например. Вы можете включить атрибут проверки ошибок в своем мьютексе. Ошибка проверки мьютексов возвращает EDEADLK, если вы пытаетесь заблокировать один и тот же один дважды, и EPERM, если вы разблокируете мьютекс, который не ваш.

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");
2 голосов
/ 19 марта 2013

Mutex используется для защиты конфиденциального кода и данных, семафор используется для синхронизации. Вы также можете иметь практическое применение для защиты чувствительного кода, но может существовать риск, что снятие защиты другим потоком с помощью операции V. Таким образом, основное различие между би-семафором и мьютексом - это владение. Например, в туалете Mutex похож на то, что можно войти в туалет и запереть дверь, никто не может войти, пока человек не выйдет, би-семафор такой Можно войти в туалет и запереть дверь, но кто-то другой может войти, попросив администратора открыть дверь, это смешно.

1 голос
/ 15 сентября 2008

Ответ может зависеть от целевой ОС. Например, по крайней мере одна из знакомых мне реализаций RTOS позволит выполнять несколько последовательных операций «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.
}

Конечно, при использовании этой функции вы должны быть уверены, что все обращения в пределах одного потока действительно безопасны!

Я не уверен, насколько распространен этот подход или применяется ли он вне систем, с которыми я знаком. Пример такого типа мьютекса см. В RTOS ThreadX.

1 голос
/ 10 февраля 2016

Как уже упоминали многие, мьютекс используется для защиты критического фрагмента кода (критический раздел AKA). Вы получите мьютекс (блокировку), войдите в критический раздел и освободите мьютекс (разблокировку) все в той же теме .

При использовании семафора вы можете заставить поток ждать семафор (скажем, поток A), пока другой поток (скажем, поток B) не выполнит какую-либо задачу, а затем установить семафор для потока A, чтобы остановить ожидание, и продолжить его задача.

1 голос
/ 15 октября 2015

Мьютекс и двоичный семафор используются одинаково, но в действительности они различны.

В случае мьютекса, разблокировать его может только заблокированный поток. Если какой-то другой поток придет, чтобы заблокировать его, он будет ждать.

В случае с semaphone это не так. Семафор не связан с конкретным идентификатором потока.

1 голос
/ 02 марта 2012

Мьютексы имеют право собственности, в отличие от семафоров. Хотя любой поток в рамках мьютекса может получить разблокированный мьютекс и заблокировать доступ к тому же критическому разделу кода, только поток, который заблокировал мьютекс , должен разблокировать его .

0 голосов
/ 23 мая 2019

«двоичный семафор» - это обход языка программирования для использования «семафора», такого как «mutex». Видимо, есть две очень большие различия:

  1. То, как вы называете каждого из них.

  2. Максимальная длина «идентификатора».

0 голосов
/ 28 декабря 2015

Практически все вышесказанное говорит правильно. Позвольте мне также попытаться уточнить, есть ли у кого-то еще сомнения. Mutex -> используется для сериализации Семафор-> Синхронизация. Назначение обоих различно, однако, одинаковые функциональные возможности могут быть достигнуты благодаря тщательному программированию. Стандартный пример-> проблема производителя с потребителем. начальное значение SemaVar = 0

Производитель Потребитель --- SemaWait () -> уменьшить SemaVar

производить данные

SemaSignal SemaVar или SemaVar ++ ---> потребитель разблокирует, поскольку SemVar теперь равен 1.

Надеюсь, я смогу уточнить.

...