이진 세마포어와 뮤텍스 사이에 차이점이 있습니까? 아니면 본질적으로 동일합니까?
이진 세마포어와 뮤텍스 사이에 차이점이 있습니까? 아니면 본질적으로 동일합니까?
답변:
그들은이다 NOT 같은 일. 그들은 다른 목적으로 사용됩니다!
두 유형의 세마포어가 전체 / 빈 상태이며 동일한 API를 사용하지만 사용법은 매우 다릅니다.
상호 배제 세마포어
상호 배제 세마포어는 공유 리소스 (데이터 구조, 파일 등)를 보호하는 데 사용됩니다.
Mutex 세마포어는 그것을 수행하는 작업에 의해 "소유"됩니다. 작업 B가 작업 A가 현재 보유하고있는 뮤텍스를 표시하려고하면 작업 B의 호출이 오류를 반환하고 실패합니다.
뮤텍스는 항상 다음 순서를 사용합니다.
-SemTake -중요 섹션 -SemGive
다음은 간단한 예입니다.
스레드 A 스레드 B 뮤텍스를 액세스 데이터 ... Mutex 사용 <== 차단 ... Mutex 액세스 데이터 제공 <== 차단 해제 ... 뮤텍스 제공
이진 세마포
이진 세마포는 완전히 다른 질문을 다룹니다.
Task A Task B
... Take BinSemaphore <== wait for something
Do Something Noteworthy
Give BinSemaphore do something <== unblocks
이진 세마포어를 사용하면 B가 세마포어를 사용하고 A를 지정하는 것이 좋습니다.
이진 세마포어는 리소스 액세스를 보호하지 않습니다. 세마포어를주고받는 행위는 근본적으로 분리되어 있습니다.
일반적으로 동일한 작업에 대해 동일한 이진 세마포어를주고받는 것이 거의 의미가 없습니다.
따라서 세마포어는 생산자 소비자와 같은 일부 동기화 문제에 더 적합합니다.
Windows에서 이진 세마포어는 뮤텍스보다 이벤트 객체와 유사합니다.
Mutex can be released only by thread that had acquired it
-방금 간단한 pthread_mutex 기반 프로그램을 사용해 보았습니다. 스레드는 메인 스레드에 뮤텍스를 잠금 해제 할 수 있습니다
화장실 예제 는 즐거운 유추입니다.
뮤텍스 :
화장실의 열쇠입니다. 한 번에 한 사람이 화장실을 차지하는 열쇠를 가질 수 있습니다. 완료되면, 사람은 대기열에있는 다음 사람에게 키를 제공합니다.
공식적으로 : "뮤텍스는 일반적으로 하나 이상의 스레드가 동시에 실행할 수없는 재진입 코드 섹션에 대한 액세스를 직렬화하는 데 사용됩니다. 뮤텍스 객체는 하나의 스레드를 제어 된 섹션으로 만 허용하여 다른 스레드가 액세스하려고 시도합니다. 첫 번째 스레드가 해당 섹션에서 나올 때까지 해당 섹션을 기다리십시오. " 참고 : Symbian 개발자 라이브러리
(뮤텍스는 실제로 값이 1 인 세마포입니다.)
신호기:
동일한 무료 화장실 키의 수입니다. 예를 들어, 자물쇠와 열쇠가 같은 화장실이 4 개 있다고 가정합니다. 세마포어 수 (키 수)는 처음에 4로 설정되고 (4 개의 화장실은 모두 무료) 사람들이 들어 오면 카운트 값이 감소합니다. 모든 화장실이 가득 찬 경우, 즉 남아있는 빈 키가 없으면 세마포어 카운트는 0입니다. 이제 eq. 한 사람이 화장실을 떠나면 세마포어가 1 (무료 키)로 증가하고 대기열의 다음 사람에게 제공됩니다.
공식적으로 : "세마포어는 공유 리소스의 동시 사용자 수를 최대 수로 제한합니다. 스레드는 리소스에 대한 액세스를 요청 (세마포 감소)하고 리소스 사용이 완료되었음을 알리는 신호를 줄 수 있습니다 (세마포 증가). " 참고 : Symbian 개발자 라이브러리
주제에 대한 좋은 기사 :
2 부에서 :
뮤텍스는 하나의 중요한 차이점 인 소유권 원칙이라는 점에서 이진 세마포어의 원리와 유사합니다. 소유권은 작업이 뮤텍스를 잠 그거나 (취득 할 때) 잠금 해제 (릴리스) 할 수있는 간단한 개념입니다. 작업이 뮤텍스의 잠금을 해제하려고 시도하면 잠기지 않았으므로 (따라서 소유하지 않음) 오류 조건이 발생하며 가장 중요한 것은 뮤텍스가 잠금 해제되지 않은 것입니다. 상호 배제 객체에 소유권이없는 경우 객체와 상관없이 뮤텍스가 아닙니다.
위의 답변 중 어느 것도 혼란을 해결하지 못하므로 여기 내 혼란을 해결 한 것이 있습니다.
엄밀히 말하면, 뮤텍스는 리소스에 대한 액세스를 동기화 하는 데 사용되는 잠금 메커니즘 입니다. 하나의 작업 (OS 추상화에 기반한 스레드 또는 프로세스 일 수 있음) 만 뮤텍스를 획득 할 수 있습니다. 이는 mutex와 관련된 소유권이 있으며 소유자 만 잠금 (mutex)을 해제 할 수 있음을 의미합니다.
세마포어는 신호 전달 메커니즘입니다 (“완료되었습니다. 계속 진행할 수 있습니다”). 예를 들어, 모바일에서 노래를 듣고 (한 작업으로 가정) 친구가 전화를 걸면 인터럽트 서비스 루틴 (ISR)이 호출 처리 작업을 깨우도록 신호를주는 인터럽트가 트리거됩니다. .
그들의 동기화 의미는 매우 다릅니다 :
따라서 뮤텍스를 작업에서 작업으로 전달 된 토큰으로, 세마포어를 트래픽 빨간색 표시등으로 볼 수 있습니다 (누군가 진행할 수 있음을 알리는 신호 ).
이론적으로는 의미 적으로 다르지 않습니다. 세마포어를 사용하거나 그 반대로 뮤텍스를 구현할 수 있습니다 ( 예는 여기 참조 ). 실제로는 구현 방식이 다르며 약간 다른 서비스를 제공합니다.
실질적인 차이 (그들을 둘러싼 시스템 서비스의 관점에서)는 뮤텍스의 구현이보다 가벼운 동기화 메커니즘이라는 것을 목표로합니다. oracle-speak에서 뮤텍스는 래치로 , 세마포어는 대기 로 알려져 있습니다 .
가장 낮은 수준에서는 원자 테스트 및 설정 메커니즘을 사용합니다. 이것은 메모리 위치의 현재 값을 읽고, 일종의 조건부 조건을 계산하고, 중단 될 수없는 단일 명령으로 해당 위치의 값을 씁니다 . 즉, 뮤텍스를 획득하고 다른 사람이 뮤텍스를 가지고 있는지 확인하기 위해 테스트 할 수 있습니다.
일반적인 뮤텍스 구현에는 테스트 및 설정 명령어를 실행하고 다른 어떤 것이 뮤텍스를 설정했는지 평가하는 프로세스 또는 스레드가 있습니다. 여기서 중요한 점은 스케줄러 와 상호 작용이 없기 때문에 누가 잠금을 설정했는지 알 수 없습니다. 그런 다음 시간 조각을 포기하고 작업이 다시 예약 될 때 다시 시도하거나 spin-lock을 실행합니다 . 스핀 잠금은 다음과 같은 알고리즘입니다.
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.
보호 된 코드 ( critical section ) 실행을 마치면 뮤텍스 값을 0 또는 'clear'라는 의미로 설정하면됩니다. 여러 작업이 뮤텍스를 획득하려고 시도하는 경우 뮤텍스가 릴리스 된 후 예약 된 다음 작업은 리소스에 액세스 할 수 있습니다. 일반적으로 뮤텍스를 사용하여 독점 액세스가 매우 짧은 시간 동안 만 필요한 경우 일반적으로 공유 데이터 구조를 업데이트하는 동기화 된 리소스를 제어합니다.
세마포어는 뮤텍스 라이브러리보다 약간 더 깊이있는 스케줄러와 상호 작용하는 카운트 및 일부 시스템 호출 래퍼가있는 동기화 된 데이터 구조 (일반적으로 뮤텍스 사용)입니다. 세마포어는 증가하고 감소하여 다른 준비가 될 때까지 작업 을 차단 하는 데 사용됩니다 . 이에 대한 간단한 예는 생산자 / 소비자 문제 를 참조하십시오 . 세마포어는 어떤 값으로 초기화됩니다-이진 세마포어는 세마포어가 1로 초기화되는 특별한 경우입니다. 세마포어에 게시하면 대기 프로세스를 깨우는 효과가 있습니다.
기본 세마포어 알고리즘은 다음과 같습니다.
(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.
이진 세마포어의 경우 두 데이터 간의 주요 실제 차이점은 실제 데이터 구조를 둘러싼 시스템 서비스의 특성입니다.
편집 : 에반이 올바르게 지적했듯이 스핀 락은 단일 프로세서 시스템을 느리게합니다. 단일 프로세서에서는 다른 작업이 실행되는 동안 뮤텍스를 유지하는 프로세스가이를 재설정하지 않기 때문에 다중 프로세서 상자에서만 스핀 락을 사용합니다. 스핀 록은 다중 프로세서 아키텍처에서만 유용합니다.
futex
시스템 호출은 지연 시간이 짧은 사용자 공간 뮤텍스 / 세마포어 구현을 지원하기 위해 존재합니다. en.wikipedia.org/wiki/Futex ) 경합이없는 빠른 경로에서, 또는 리소스를 곧 사용할 수있게되면 시스템 호출. 그러나 바쁘게 기다리는 동안 몇 초를 소비하지 않습니다. 스핀 루프 백 오프 및 대기의 매개 변수 조정은 물론 하드웨어 및 작업 부하에 따라 다르지만 표준 라이브러리는 일반적으로 합리적인 선택이 있습니다.
뮤텍스 및 세마포어는 동기화 프리미티브로 사용되지만 이들 사이에는 큰 차이가 있습니다. 뮤텍스의 경우 뮤텍스를 잠 그거나 획득 한 스레드 만 잠금을 해제 할 수 있습니다. 세마포어의 경우, 세마포어를 기다리는 스레드는 다른 스레드에 의해 시그널링 될 수있다. 일부 운영 체제는 프로세스 간 뮤텍스 및 세마포어 사용을 지원합니다. 일반적으로 사용량은 공유 메모리에서 생성됩니다.
Mutex : 임계 섹션 스레드 T1이 액세스하려는 경우 아래 단계를 따릅니다. T1 :
이진 세마포어 : 신호 대기 및 신호를 기반으로 작동합니다. wait (s)는 "s"값을 1 씩 감소시킵니다. 일반적으로 "s"값은 "1"값으로 초기화되고, 신호는 "s"값을 1 씩 증가시킵니다. "s"값이 1이면 아무도 임계 섹션을 사용하고 있지 않고, 값이 0이면 임계 섹션이 사용 중임을 의미합니다. 스레드 T2가 임계 섹션을 사용하고 있다고 가정하면 아래 단계를 따릅니다. T2 :
Mutex와 바이너리 세마포어의 주요 차이점은 스레드가 중요 섹션을 잠그면 중요 텍스트 섹션을 잠금 해제 해야하는 경우 Mutext에 있으며 다른 스레드는 잠금을 해제 할 수 없지만 바이너리 스레드의 경우 하나의 스레드가 대기 기능을 사용하여 중요 섹션을 잠그면 값 s의 값이 "0"이되고 "s"의 값이 1이 될 때까지 아무도 액세스 할 수 없지만 다른 스레드가 신호를 호출 한 다음 "s"의 값이 1이되고 다른 함수가 중요한 섹션을 사용할 수 있다고 가정합니다. 따라서 이진 세마포어 스레드에는 소유권이 없습니다.
Windows에서 뮤텍스와 이진 세마포어에는 두 가지 차이점이 있습니다.
뮤텍스는 소유권이있는 스레드, 즉 이전에 대기 기능을 호출 한 스레드 (또는 생성시 소유권을 가져온 스레드) 만 해제 할 수 있습니다. 모든 스레드에서 세마포어를 해제 할 수 있습니다.
스레드는 차단하지 않고 뮤텍스에서 대기 함수를 반복해서 호출 할 수 있습니다. 그러나 사이에 세마포어를 해제하지 않고 이진 세마포어에서 대기 함수를 두 번 호출하면 스레드가 차단됩니다.
분명히 뮤텍스를 사용하여 한 스레드에서 다른 스레드가 동시에 액세스하는 데이터를 잠급니다. 방금 전화를 걸어 lock()
데이터에 액세스하는 중이라고 가정하십시오 . 이것은 다른 스레드 (또는 동일한 스레드 코드의 다른 인스턴스)가 동일한 뮤텍스에 의해 잠긴 동일한 데이터에 액세스하지 않을 것을 의미합니다. 즉, 다른 스레드 인스턴스에서 동일한 스레드 코드가 실행되면 잠금을 누른 다음lock()
제어 흐름을 차단해야합니다. 이것은 다른 스레드 코드를 사용하는 스레드에 적용되며, 동일한 스레드 코드에도 동일한 데이터에 액세스하고 동일한 뮤텍스에 의해 잠겨 있습니다. 이 경우 여전히 데이터에 액세스하는 과정에 있으며 뮤텍스 잠금 해제에 도달하는 데 15 초가 더 걸릴 수 있습니다. 데이터에 액세스). 다른 스레드가 동일한 뮤텍스를 잠금 해제하고 뮤텍스 잠금에서 이미 대기중인 (블로킹) 스레드가 데이터를 차단 해제하고 액세스 할 수 있도록 허용합니까? 내가 여기서 뭐라고하길 바래? 당연히 보편적 정의에 동의했다!
따라서 mutex 대신 binary-semaphore를 사용하는 것이 매우 중요하다면 잠금 및 잠금 해제의“범위 지정”에 매우주의해야합니다. 모든 잠금에 부딪힌 모든 제어 흐름은 잠금 해제 호출에 도달해야하며 "첫 번째 잠금 해제"도 없어야하며 항상 "첫 번째 잠금"이어야합니다.
신화:
"이진 세마포어와 뮤텍스가 동일하다"또는 "값이 1 인 세마포어가 뮤텍스이다"라는 기본 기사는 Mutex를 획득 한 스레드 만 해제 할 수 있지만 다른 스레드에서 세마포어를 표시 할 수 있다는 기본적인 차이점은
키 포인트:
• 스레드는 둘 이상의 잠금 (Mutex)을 획득 할 수 있습니다.
• 재귀 뮤텍스, 뮤텍스에 대한 잠금 및 잠금 해제가 동일 해야하는 경우에만 뮤텍스를 두 번 이상 잠글 수 있습니다
• 이미 뮤텍스를 잠근 스레드가 뮤텍스를 다시 잠그려고하면 해당 뮤텍스의 대기 목록에 들어가 교착 상태가 발생합니다.
• 이진 세마포어와 뮤텍스는 비슷하지만 동일하지 않습니다.
• Mutex는 관련 보호 프로토콜로 인해 비용이 많이 듭니다.
• 뮤텍스의 주요 목표는 원자 적 액세스 또는 리소스 잠금을 달성하는 것입니다.
뮤텍스는 하나의 공유 리소스에 대한 액세스를 제어합니다. 해당 자원에 대한 액세스 를 확보 () 하고 완료되면 해제 () 하는 조작을 제공합니다 .
세마포어 자원의 공유 풀에 대한 액세스를 제어합니다. 풀의 자원 중 하나가 사용 가능해질 때까지 Wait () 및 풀에 다시 제공 될 때 Signal ()에 조작을 제공 합니다.
세마포가 보호하는 자원의 수가 1보다 크면이를 세마포어 계수 라고합니다 . 하나의 리소스를 제어 할 때 부울 세마포 라고합니다. . 부울 세마포어는 뮤텍스와 같습니다.
따라서 세마포어는 뮤텍스보다 더 높은 수준의 추상화입니다. 뮤텍스는 세마포어를 사용하여 구현할 수 있지만 다른 방법은 아닙니다.
수정 된 질문은 "Linux"에서 뮤텍스와 "이진"세마포어의 차이점은 무엇입니까?
답변 : 다음은 차이점입니다. – i) 범위 – 뮤텍스의 범위는 프로세스 주소 공간 내에 있으며 뮤텍스의 범위는 스레드를 동기화하는 데 사용됩니다. 세마포어는 프로세스 공간에서 사용될 수있는 반면 프로세스 간 동기화에 사용될 수 있습니다.
ii) 뮤텍스는 세마포어보다 가볍고 빠릅니다. Futex가 훨씬 빠릅니다.
iii) Mutex는 동일한 횟수만큼 해제해야한다는 조건으로 동일한 스레드에서 여러 번 성공적으로 획득 할 수 있습니다. 획득하려는 다른 스레드가 차단됩니다. 세마포어의 경우 동일한 프로세스가 다시 획득하려고하면 한 번만 획득 할 수 있으므로 차단됩니다.
뮤텍스는 중요한 지역을 차단하는 데 일하지만 세마포는 중요한 일을합니다.
http://www.geeksforgeeks.org/archives/9102 에서 자세히 설명합니다.
Mutex
리소스에 대한 액세스를 동기화하는 데 사용되는 잠금 메커니즘입니다.
Semaphore
신호 메커니즘입니다.
뮤텍스 대신 이진 세마포어를 사용하려는 경우 프로그래머에게 달려 있습니다.
뮤텍스에 소유자가 있다는 사실 외에도 두 객체는 서로 다른 용도로 최적화 될 수 있습니다. 뮤텍스는 짧은 시간 동안 만 유지되도록 설계되었습니다. 이를 위반하면 성능이 저하되고 일정이 잘못 될 수 있습니다. 예를 들어, 실행중인 스레드는 다른 스레드가 이미 차단되어 있어도 뮤텍스를 획득 할 수 있습니다. 세마포어가 더 공정성을 제공하거나 여러 조건 변수를 사용하여 공정성을 강요 할 수 있습니다.
sem_post()
대한 SCHED_FIFO
과 SCHED_RR
(이 두 가지가 기본되지 않음) : 가장 높은 우선 순위의 스레드를, 같은 우선 순위가 가장 긴 대기 된 스레드와 다중이있는 경우. OpenSolaris는 정상적인 스케쥴링에서도이 FIFO 규칙을 어느 정도 따릅니다. glibc와 FreeBSD의 경우 간단한 뮤텍스 잠금 해제 (즉, 우선 순위 보호 또는 우선 순위 상속이 아님)와 세마포어 게시는 기본적으로 동일하며 객체를 잠금 해제 된 것으로 표시 한 다음 대기중인 스레드가있을 경우 커널을 호출하여 깨우도록합니다.
이진 세마포어가 뮤텍스로 사용될 수 있지만, 뮤텍스는 뮤텍스를 잠근 프로세스 만 잠금을 해제해야한다는 점에서보다 구체적인 사용 사례입니다. 이 소유권 제약으로 다음에 대한 보호 기능을 제공 할 수 있습니다.
이러한 제한은 속도를 저하시키기 때문에 항상 존재하는 것은 아닙니다. 코드를 개발하는 동안 이러한 검사를 일시적으로 활성화 할 수 있습니다.
예를 들어 뮤텍스에서 Error check 속성을 활성화 할 수 있습니다. 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");
위의 게시물을 살펴본 후 개념이 명확했습니다. 그러나 몇 가지 남아있는 질문이있었습니다. 그래서이 작은 코드를 작성했습니다.
우리가 세마포어를 가져 가지 않고 주려고 할 때, 그것은 통과합니다. 그러나 뮤텍스를 가져 가지 않고 주려고하면 실패합니다. 나는 이것을 Windows 플랫폼에서 테스트했습니다. MUTEX를 사용하여 동일한 코드를 실행하려면 USE_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;
}
세마포어가 리소스를 소유 한 적이 없더라도 "리소스를 사용하여 완료되었습니다"라는 신호를 보낼 수 있다는 사실은 세마포어의 경우 소유와 신호 사이에 매우 느슨한 결합이 있다고 생각합니다.
뮤텍스
뮤텍스는 일반적으로 둘 이상의 스레드가 동시에 실행할 수없는 재진입 코드 섹션에 대한 액세스를 직렬화하는 데 사용됩니다. 뮤텍스 객체는 하나의 스레드를 제어 된 섹션으로 만 허용하여 해당 섹션에 액세스하려는 다른 스레드가 해당 섹션에서 첫 번째 스레드가 종료 될 때까지 대기하도록합니다. 의도하지 않은 부작용. 서로 다른 우선 순위로 작동하고 뮤텍스를 통해 조정되는 두 가지 RTOS 작업은 우선 순위 반전 의 기회를 만듭니다 . Mutex는 사용자 공간 에서 작동 합니다 .
신호기
세마포는 신호 메커니즘입니다. 세마포어는 공유 리소스의 동시 사용자 수를 최대 수로 제한합니다. 스레드는 리소스에 대한 액세스를 요청하고 (세마포 감소) 리소스 사용이 완료되었음을 알리는 (세마포 증가) 신호를 보낼 수 있습니다. 스레드 수는 공유 리소스에 액세스 할 수 있습니다. 세마포어의 올바른 사용은 한 작업에서 다른 작업으로 신호를 보내는 데 사용되며, 세마포어를 사용하여 인터럽트 서비스 루틴 (ISR)에서 작업 으로 신호를 보낼 수도 있습니다 . 세마포 신호는 비 차단 RTOS 동작이므로 ISR 안전합니다. 이 기술은 오류가 발생하기 쉬운 작업 수준에서 인터럽트를 비활성화 할 필요가 없으므로 커널 공간 에서 작동 합니다 .
대답은 대상 OS에 따라 다를 수 있습니다. 예를 들어, 내가 익숙한 하나 이상의 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 RTOS를 참조하십시오.
최고의 솔루션
유일한 차이점은
1. Mutex-> 잠금 및 잠금 해제는 뮤텍스를 잠그는 스레드의 소유권입니다.
2. 세마포어-> 소유권 없음; 하나의 스레드가 semwait를 호출하면 다른 스레드는 sempost를 호출하여 잠금을 제거 할 수 있습니다.
뮤텍스
최근까지 커널에서 유일한 잠자기 잠금은 세마포어였습니다. 대부분의 세마포어 사용자는 세마포어를 1 개로 인스턴스화하여 상호 배제 잠금 (spin-lock의 수면 버전)으로 취급했습니다. 불행하게도, 세마포어는 다소 일반적이며 사용 제약을 부과하지 않습니다. 이는 커널과 사용자 공간 사이의 복잡한 춤과 같이 모호한 상황에서 독점 액세스를 관리하는 데 유용합니다. 그러나 이는 단순한 잠금이 더 어려워지고 시행 규칙이 없기 때문에 모든 종류의 자동 디버깅 또는 제약 조건 시행이 불가능하다는 것을 의미합니다. 보다 간단한 수면 잠금 장치를 찾기 위해 커널 개발자는 뮤텍스를 도입했습니다. "뮤텍스"라는 용어는 상호 배제를 강제하는 모든 수면 잠금 장치를 지칭하는 일반적인 이름입니다. 사용량이 1 인 세마포어와 같은 최근 Linux 커널에서 올바른 명사“mutex”는 이제 상호 배제를 구현하는 특정 유형의 수면 잠금 장치입니다. 즉, mutex는 mutex입니다.
뮤텍스의 단순성과 효율성은 세마포어가 요구하는 것 이상으로 사용자에게 부과하는 추가 제약에서 비롯됩니다. Dijkstra의 독창적 인 디자인에 따라 가장 기본적인 동작을 구현하는 세마포어와 달리 뮤텍스는 더 엄격하고 좁은 사용 사례를 갖습니다. n 한 번에 하나의 작업 만 뮤텍스를 유지할 수 있습니다. 즉, 뮤텍스의 사용량은 항상 하나입니다.
[1] 리눅스 커널 개발, 제 3 판 Robert Love
나는 뮤텍스가 그것을 보유하고있는 프로세스에 의해서만 릴리스 될 수 있지만 세마포어는 ay 프로세스에 의해 시그널링 될 수 있다고 말하는 사람들의 대답이 혼란 스럽다고 생각합니다. 위의 줄은 세마포어 측면에서 모호합니다. 이해하기 위해 세마포어에는 두 가지 종류가 있으며, 하나는 카운팅 세마포어이고 다른 하나는 이진 세마포어입니다. 계산에서 세마포어는 사용하기 전에 n을 정의 할 수있는 n 개의 리소스에 대한 액세스를 처리합니다. 각 세마포어에는 count 변수가 있습니다.이 변수는 사용중인 리소스 수의 개수를 유지하며 처음에는 n으로 설정됩니다. 리소스를 사용하려는 각 프로세스는 세마포어에서 wait () 작업을 수행하여 카운트를 줄입니다. 프로세스가 자원을 해제하면 release () 작업을 수행합니다 (카운트 증가). 카운트가 0이되면 모든 자원이 사용되고 있습니다. 그 후, 프로세스는 계수가 0보다 커질 때까지 대기합니다. 이제 자원을 보유하는 프로세스 만이 계수를 증가시킬 수 있습니다. 다른 프로세스는 계수를 증가시킬 수 없습니다. 자원을 보유한 프로세스 만이 계수를 증가시킬 수 있습니다. 세마포어를 다시 확인하면 사용 가능한 리소스가 표시되면 카운트가 다시 줄어 듭니다. 따라서 이진 세마포어 측면에서 세마포어를 보유한 프로세스 만 카운트를 증가시킬 수 있으며, 세마포어 사용을 중지하고 카운트를 증가시킬 때까지 카운트는 0으로 유지되며 다른 프로세스는 세마포어에 액세스 할 수 있습니다. 이제는 리소스를 보유한 프로세스 만 카운트를 늘릴 수 있습니다. 다른 프로세스는 카운트를 늘릴 수 없습니다. 리소스를 보유한 프로세스 만 카운트를 늘릴 수 있고 세마포어를 다시 기다리는 프로세스는 리소스를 사용할 수있을 때 볼 수 있습니다 카운트를 다시 줄입니다. 따라서 이진 세마포어 측면에서 세마포어를 보유한 프로세스 만 카운트를 증가시킬 수 있으며, 세마포어 사용을 중지하고 카운트를 증가시킬 때까지 카운트는 0으로 유지되며 다른 프로세스는 세마포어에 액세스 할 수 있습니다. 이제는 리소스를 보유한 프로세스 만 카운트를 늘릴 수 있습니다. 다른 프로세스는 카운트를 늘릴 수 없습니다. 리소스를 보유한 프로세스 만 카운트를 늘릴 수 있고 세마포어를 다시 기다리는 프로세스는 리소스를 사용할 수있을 때 볼 수 있습니다 카운트를 다시 줄입니다. 따라서 이진 세마포어 측면에서 세마포어를 보유한 프로세스 만 카운트를 증가시킬 수 있으며, 세마포어 사용을 중지하고 카운트를 증가시킬 때까지 카운트는 0으로 유지되며 다른 프로세스는 세마포어에 액세스 할 수 있습니다.
이진 세마포어와 뮤텍스의 주요 차이점은 세마포어가 신호 메커니즘이고 뮤텍스가 잠금 메커니즘이지만 이진 세마포어는 혼동을 일으키는 뮤텍스처럼 작동하는 것 같지만 둘 다 다른 종류의 작업에 적합한 다른 개념입니다.