operating system - 인터럽트 - 바이너리 세마포어와 뮤텍스의 차이점




안드로이드 뮤텍스 (20)

Windows에서 뮤텍스와 바이너리 세마포어에는 두 가지 차이점이 있습니다.

  1. 뮤텍스는 이전에 Wait 함수를 호출 한 스레드 (또는 스레드를 생성 할 때 소유권을 가짐)가 소유 한 스레드에서만 릴리스 될 수 있습니다. 세마포어는 모든 스레드에 의해 해제 될 수 있습니다.

  2. 스레드는 차단하지 않고 뮤텍스에서 반복적으로 대기 함수를 호출 할 수 있습니다. 그러나 중간에 세마포어를 해제하지 않고 바이너리 세마포어에서 대기 함수를 두 번 호출하면 스레드가 차단됩니다.

바이너리 세마포어와 뮤텍스간에 차이가 있습니까? 아니면 본질적으로 동일합니까?


mutex에 소유자가 있다는 사실 외에도 두 객체는 ​​서로 다른 용도로 최적화 될 수 있습니다. 뮤텍스는 짧은 시간 동안 만 개최되도록 설계되었습니다. 이를 위반하면 성능 저하 및 불공정 한 스케줄링이 발생할 수 있습니다. 예를 들어, 실행중인 스레드는 다른 스레드가 이미 차단되어 있어도 뮤텍스를 획득하도록 허용 될 수 있습니다. 세마포어는보다 공정성을 제공 할 수 있으며, 공정성은 여러 조건 변수를 사용하여 강제 될 수 있습니다.


대답은 대상 OS에 따라 다를 수 있습니다. 예를 들어, 내가 익숙한 적어도 하나의 RTOS 구현은 동일한 스레드 컨텍스트 내에서 모두 발생하는 한 단일 OS 뮤텍스에 대해 여러 차례 순차적 인 "get"연산을 허용합니다. 다른 thread가 뮤텍스를 취득하기 전에, 복수의 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 RTOS를 참조하십시오.


동기화 의미론은 매우 다릅니다.

  • 뮤텍스 (mutex)는 주어진 자원에 대한 접근을 직렬화 할 수있게한다. 즉, 한번에 하나씩 여러개의 쓰레드가 잠금을 기다린다. 이전에 말했듯이, 쓰레드는 완료 될 때까지 잠금을 소유 한다.
  • 바이너리 세마포어는 값 0과 1을 가진 카운터입니다. 어떤 작업이 sem_post를 수행 할 때까지 작업을 차단합니다. 세마포어는 리소스가 사용 가능하다는 것을 알리고 사용 가능한 것으로 신호 될 때까지 기다릴 수있는 메커니즘을 제공합니다.

이와 같이 태스크에서 태스크로 전달되는 토큰으로 뮤텍스를 볼 수 있으며, 트래픽 적색 등으로 세마포어를 볼 수 있습니다.


뮤텍스는 "잠금 장치"에 사용됩니다. 한 번에 하나의 프로세스가 공유 리소스를 사용할 수 있습니다.

이므로

세마포어는 "완료되었습니다. 이제 계속할 수 있습니다"와 같은 "신호 메커니즘"에 사용됩니다.


뮤텍스는 다른 스레드 (또는 프로세스)에서 세마포어를 신호로 보낼 수있는 동안 획득 한 스레드에 의해서만 릴리스 될 수 있으므로 세마포어는 생산자 - 소비자와 같은 일부 동기화 문제에 더 적합합니다.

Windows에서 바이너리 세마포어는 뮤텍스보다 이벤트 객체에 가깝습니다.


뮤텍스와 세마포어가 동기화 프리미티브로 사용되었지만 이들 사이에는 큰 차이가 있습니다. 뮤텍스의 경우, 뮤텍스를 잠 그거나 획득 한 스레드 만 잠금을 해제 할 수 있습니다. 세마포어의 경우, 세마포어를 기다리는 쓰레드는 다른 쓰레드에 의해 시그널링 될 수있다. 일부 운영 체제에서는 프로세스간에 뮤텍스 및 세마포를 사용하는 것을 지원합니다. 일반적으로 사용량은 공유 메모리에서 생성됩니다.


바이너리 세마포어는 뮤텍스로 사용될 수 있지만, 뮤텍스는 잠겨있는 프로세스 만 잠금을 해제해야한다는 점에서보다 구체적인 유스 케이스입니다. 이 소유권 제약은 다음에 대한 보호를 제공 할 수 있습니다.

  • 우발적 인 석방
  • 재귀 적 교착 상태
  • 작업 죽음 교착 상태

이러한 제약 조건은 속도를 떨어 뜨리기 때문에 항상 존재하지는 않습니다. 코드를 개발하는 동안 이러한 검사를 일시적으로 사용할 수 있습니다.

예를 들어 뮤텍스에서 Error check 속성을 활성화 할 수 있습니다. 뮤텍스 검사 오류는 동일한 EDEADLK 두 번 잠그려고하면 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");

분명히 mutex를 사용하여 한 스레드의 데이터를 다른 스레드가 동시에 액세스 할 수 있도록 잠급니다. lock() 을 방금 호출했고 데이터에 액세스하는 과정에 있다고 가정합니다. 이는 다른 스레드 (또는 동일한 스레드 코드의 다른 인스턴스)가 동일한 뮤텍스에 의해 잠긴 동일한 데이터에 액세스하는 것을 기대하지 않는다는 것을 의미합니다. 즉, 다른 스레드 인스턴스에서 실행되는 동일한 스레드 코드가 잠금에 도달하면 lock() 이 제어 흐름을 차단해야합니다. 이것은 동일한 스레드 코드를 사용하는 스레드에 적용됩니다.이 스레드 코드는 동일한 데이터에 액세스하고 있으며 동일한 뮤텍스에 의해 잠겨 있습니다. 이 경우에도 데이터 액세스 프로세스가 진행 중이고 다른 15 초 동안 뮤텍스 잠금 해제에 도달 할 수 있습니다 (따라서 뮤텍스 잠금으로 차단 된 다른 스레드는 차단 해제되어 제어가 허용됩니다). 데이터에 액세스). 어떤 비용으로도 다른 스레드가 동일한 뮤텍스를 잠금 해제 할 수있게하고 뮤텍스 잠금에서 이미 대기중인 (차단) 스레드가 데이터를 차단 해제하고 액세스하도록 허용합니까? 내가 여기서 말하는 것을 가지고 있기를 바래요? 당연히, 보편적 인 정의에 합의했습니다!

  • "뮤텍스 (mutex)"로는 이런 일이 일어날 수 없다. 다른 스레드가 스레드의 잠금을 해제 할 수 없습니다.
  • "바이너리 - 세마포어"가 생길 수 있습니다. 다른 스레드가 스레드의 잠금을 해제 할 수 있습니다.

따라서 뮤텍스 대신 바이너리 세마포어를 사용하는 것이 매우 중요하다면 잠금 및 잠금 해제의 "범위 지정"에 매우주의해야합니다. 모든 잠금을 치는 모든 제어 흐름이 잠금 해제 호출에 충돌해야하며 "첫 번째 잠금 해제"가 없어야하며 항상 "첫 번째 잠금"이어야합니다.


수정 된 질문은 - "Linux"에서 뮤텍스와 "바이너리"세마포어의 차이점은 무엇입니까?

Ans : 다음은 차이점입니다. i) 범위 - 뮤텍스의 범위는 스레드를 생성하고 스레드 동기화에 사용되는 프로세스 주소 공간 내에 있습니다. 세마포어는 프로세스 공간에서 사용될 수 있기 때문에 프로세스 간 동기화에 사용될 수 있습니다.

ii) 뮤텍스는 가볍고 세마포보다 빠릅니다. Futex는 훨씬 빠릅니다.

iii) 뮤텍스는 동일 스레드에 의해 성공적으로 여러 번 획득 될 수있다. 획득을 시도하는 다른 스레드가 차단됩니다. 세마포어의 경우 동일한 프로세스가 다시 세마포어를 획득하려고 시도하면 세마포어는 한 번만 획득 할 수 있으므로 차단됩니다.


위의 게시물을 살펴본 후에 개념은 분명했습니다. 그러나 느린 질문이있었습니다. 그래서이 작은 코드를 썼습니다.

우리가 그것을 취하지 않고 세마포어를 주려고 할 때, 그것은 통과합니다. 그러나 뮤텍스를 가져 가지 않고 뮤텍스를 제공하려고하면 실패합니다. 나는 이것을 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;
}

위의 답변 중 어느 것도 혼란을 없애지 않으므로 여기에 내 혼란을 없애주는 답변이 있습니다.

엄밀히 말하면 뮤텍스는 리소스에 대한 액세스를 동기화 하는 데 사용되는 잠금 메커니즘 입니다. 하나의 작업 (OS 추상화에 기반한 스레드 또는 프로세스가 될 수 있음)만이 뮤텍스를 획득 할 수 있습니다. 뮤텍스와 관련된 소유권이 있으며 소유자 만 잠금 (뮤텍스)을 해제 할 수 있음을 의미합니다.

세마포어 (semaphore)는 시그널링 메커니즘입니다 ( "끝났습니다. 계속 진행할 수 있습니다"). 예를 들어 휴대 전화에서 노래를 듣고 (하나의 작업으로 가정) 친구가 전화를받는 동시에 인터럽트가 발생하여 ISR (인터럽트 서비스 루틴)이 통화 처리 작업을 깨우기 위해 신호를 보냅니다 .

출처 : http://www.geeksforgeeks.org/mutex-vs-semaphore/


임계 영역 차단에 대한 뮤텍스 작업.하지만 세마포어는 계산에 영향을 미칩니다.


주제에 대한 좋은 기사 :

2 부에서 :

뮤텍스 (mutex)는 바이너리 세마포어의 원리와 비슷하지만 중요한 차이점 중 하나는 소유권의 원칙입니다. 소유권은 태스크가 뮤텍스를 잠그는 (획득하는) 경우에만 잠금 해제 (해제) 할 수 있다는 단순한 개념입니다. 작업이 잠기지 않은 (따라서 소유하지 않은) 뮤텍스를 잠금 해제하려고 시도하면 오류 조건이 발생하며 가장 중요한 것은 뮤텍스가 잠금 해제되어 있지 않다는 것입니다. 상호 배제 객체가 소유권을 가지지 않는다면, 상호 배제 객체는 뮤텍스가 아니다.


화장실 예제 는 즐거운 비유입니다.

뮤텍스 :

화장실 열쇠입니다. 한 사람이 열쇠를 가질 수 있습니다 - 당시 화장실을 차지하십시오 -. 작업이 끝나면 대기열의 다음 사람에게 키를 제공 (해제)합니다.

공식적으로 "뮤텍스는 일반적으로 둘 이상의 스레드가 동시에 실행할 수없는 재진입 코드 섹션에 대한 액세스를 직렬화하는 데 사용됩니다. 뮤텍스 개체는 제어 섹션에 하나의 스레드 만 허용하여 액세스를 시도하는 다른 스레드를 강제합니다 그 섹션은 첫 번째 스레드가 그 섹션에서 빠져 나올 때까지 기다려야합니다. " 심판 : 심비안 개발자 라이브러리

(뮤텍스는 실제로 값이 1 인 세마포어입니다.)

신호기:

무료 동일한 화장실 키의 수입니다. 예를 들어, 동일한 자물쇠와 열쇠가있는 화장실이 4 개 있다고 가정 해보십시오. 세마포어 카운트 - 키 수 -는 처음에 4로 설정되고 (네 개의 화장실 모두 사용 가능), 사람들이 들어올 때 카운트 값이 감소합니다. 모든 화장실이 가득 찬 경우 즉, 여유 키가 남아 있지 않습니다. 세마포어 수는 0입니다. 이제, eq. 한 명은 변기를 떠나고, 세마포어는 1 (무료 키 하나)로 증가하고 대기열의 다음 사람에게 제공됩니다.

공식적으로 : "세마포어는 공유 리소스의 동시 사용자 수를 최대 수로 제한하며 스레드는 리소스에 대한 액세스를 요청할 수 있고 (세마포를 감소 시킴) 리소스 사용을 끝냈음을 알릴 수 있습니다 (세마포어 증가). " 심판 : 심비안 개발자 라이브러리


http://www.geeksforgeeks.org/archives/9102 에서 자세히 설명합니다.

Mutex 는 리소스에 대한 액세스를 동기화하는 데 사용되는 잠금 메커니즘입니다. Semaphore 는 신호 메커니즘입니다.

뮤텍스 대신 바이너리 세마포어를 사용하고자한다면 프로그래머에게 달려있다.


많은 사람들이 언급했듯이 뮤텍스는 중요한 코드 (AKA critical 섹션)를 보호하는 데 사용됩니다. 같은 스레드에서 뮤텍스 (잠금)를 획득하고 중요 섹션을 입력하며 뮤텍스를 해제합니다 (잠금 해제) .

세마포어를 사용하는 동안 다른 스레드 (예 : 스레드 B)가 어떤 작업을 완료 할 때까지 스레드를 세마포어 (예 : 스레드 A)에서 대기하게하고 스레드 A에 대한 세마포를 설정하여 대기를 중지하고 해당 작업을 계속할 수 있습니다.


뮤텍스 및 바이너리 세마포어는 모두 같은 용도이지만 실제로는 다르다. 뮤텍스의 경우에는 잠긴 스레드가 잠금을 해제 할 수 있습니다. 다른 스레드가 잠기면 기다릴 것입니다. 하지만 세마 폰의 경우에는 그렇지 않습니다. 세마포어는 부분적인 스레드 ID로 묶이지 않습니다.


위의 거의 모든 것이 옳다고 말했습니다. 누군가가 여전히 의심하는지 명확히하기 위해 내게 조금이라도 노력하겠습니다. 뮤텍스 -> 직렬화 세마포어 -> 동기화에 사용됩니다. 두 가지 목적은 다르지만 신중한 프로그래밍을 통해 두 기능을 통해 동일한 기능을 구현할 수 있습니다. 표준 사례 -> 생산자 소비자 문제. SemaVar의 초기 값 = 0

생산자 소비자 --- SemaWait () -> 감소 SemaVar

데이터를 생산하다

SemaSignal SemaVar 또는 SemaVar ++ ---> SemVar 로의 소비자 차단 해제는 1입니다.

희망을 분명히 할 수 있기를 바랍니다.


  • 정의에 따라 뮤텍스 는 둘 이상의 스레드에서 동시에 실행할 수없는 재진입 코드 섹션에 대한 액세스를 직렬화하는 데 사용됩니다.

  • 정의에 따라 세마포어 는 공유 리소스의 동시 사용자 수를 최대 개수로 제한합니다

  • 세마포어는 뮤텍스 일 수 있지만 뮤텍스는 결코 세마포어가 될 수 없습니다. 이것은 바이너리 세마포어가 사용된다는 것을 의미합니다
    뮤텍스 (Mutex)로 표시 할 수 있지만 뮤텍스는 결코 세마포어의 기능을 나타낼 수 없습니다.

  • 세마포어 (semaphore)와 뮤텍스 (Mutex) (적어도 최신 커널에서)는 본질적으로 비 재귀 적입니다.
  • 아무도 세마포를 소유하고 뮤텍스는 소유하고 소유자는 자신에 대한 책임을진다. 이것은 디버깅 관점에서 중요한 차이점입니다.
  • 뮤텍스의 경우 뮤텍스를 소유 한 스레드가 뮤텍스를 해제해야합니다. 그러나 세마포어의 경우이 조건은 필요하지 않습니다. 다른 스레드는 smps (function.e_ot)를 사용하여 세마포어를 해제하라는 신호를 보낼 수 있습니다.

  • 개발자에게 중요한 또 다른 차이점은 세마포어는 시스템 전체에 적용되며, 정리되지 않은 한 파일 시스템의 파일 형태로 유지된다는 것입니다. 뮤텍스는 프로세스 전체에 적용되며 프로세스가 종료되면 자동으로 정리됩니다.

  • 세마포어의 본질은 관련된 스레드와 관련이없는 프로세스뿐만 아니라 스레드 간의 동기화에도 사용할 수 있습니다. 뮤텍스는 스레드 간의 동기화와 관련된 프로세스 사이에서만 가능합니다 (최신 커널의 pthread 구현에는 관련 프로세스간에 Mutex를 사용할 수있는 기능이 있습니다).
  • 커널 문서에 따르면 뮤텍스는 세마포어와 비교할 때 가볍습니다. 즉, 뮤텍스가있는 프로그램과 비교할 때 세마포어 사용량이 많은 프로그램의 메모리 사용량이 더 많습니다.
  • 사용 관점에서, 뮤텍스는 세마포어와 비교할 때 더 간단한 의미를 갖는다.