[concurrency] 잠금, 뮤텍스, 세마포… 차이점은 무엇입니까?

동시 프로그래밍과 관련된 이러한 단어를 들었지만 차이점은 무엇입니까?



답변

잠금은 하나의 스레드 만 잠긴 파트에 들어갈 수있게하며 다른 프로세스와 공유되지 않습니다.

뮤텍스는 잠금과 동일하지만 시스템 전체 (여러 프로세스가 공유) 일 수 있습니다.

세마포어는 뮤텍스와 같은 작업을 수행하지만, 입력 스레드의 X 번호,이, IO를 CPU의 수를 제한하거나 동시에 실행 집약적 인 작업을 숫양 예를 들어 사용할 수 있습니다.

뮤텍스와 세마포어의 차이점에 대한 자세한 내용은 여기를 참조하십시오 .

또한 읽기 / 쓰기 잠금 기능을 사용하여 주어진 시간에 무제한의 독자 또는 1 명의 작성자를 허용합니다.


답변

이 단어들에 관해 많은 오해가 있습니다.

이것은 이전 게시물 ( https://stackoverflow.com/a/24582076/3163691 ) 에서 가져온 것입니다.

1) Critical Section = 하나의 프로세스 내 에서 다른 많은 스레드 로부터 하나의 활성 스레드 를 실행하는 데 사용되는 사용자 개체 . 선택되지 않은 다른 스레드 (@이 객체를 획득)는 휴면 상태가 됩니다.

[프로세스 기능이없고 매우 원시적 인 개체].

2) Mutex Semaphore (일명 Mutex) = 여러 프로세스 중에서 다른 많은 것 중 하나의 활성 스레드 를 실행하는 데 사용되는 커널 객체 . 선택되지 않은 다른 스레드 (@이 객체를 획득)는 휴면 상태가 됩니다. 이 객체는 스레드 소유권, 스레드 종료 알림, 재귀 (동일한 스레드에서 여러 개의 ‘취득’호출) 및 ‘우선 순위 반전 방지’를 지원합니다.

[사용하기 매우 안전한 프로세스 간 기능, 일종의 ‘고수준’동기화 개체].

3) 카운팅 세마포어 (일명 세마포어) = 많은 다른 스레드 로부터 활성 스레드 그룹을 실행하는 데 사용되는 커널 객체 . 선택되지 않은 다른 스레드 (@이 객체를 획득)는 휴면 상태가 됩니다.

[프로세스 기능은 스레드 종료 알림, 재귀?, ‘우선 순위 반전 방지’등의 ‘뮤텍스’속성이 없기 때문에 사용하기에 안전하지 않습니다.]

4) 이제 ‘스핀 록’에 대해 이야기하면서 먼저 몇 가지 정의를 정의하십시오.

Critical Region = 2 개 이상의 프로세스가 공유하는 메모리 영역.

Lock = 값이 ‘핵심 영역’으로의 진입을 허용하거나 거부하는 변수입니다. (이것은 간단한 ‘부울 플래그’로 구현 될 수 있습니다).

통화 중 대기 = 일부 값이 나타날 때까지 변수를 계속 테스트합니다.

드디어:

Spin-lock (일명 Spinlock) = 통화 중 대기 를 사용 하는 잠금 . (다음은 취득 단계 로크 가 이루어진다 XCHG 또는 유사한 원자 조작 ).

[스레드 슬리핑이 없으며 대부분 커널 레벨에서만 사용됩니다. 사용자 수준 코드에 비효율적입니다].

마지막으로, 확실하지는 않지만 위의 첫 번째 3 개의 동기화 객체 (# 1, # 2 및 # 3)가 구현의 일부로이 간단한 짐승 (# 4)을 사용한다는 큰 벅을 걸 수 있습니다.

좋은 하루 되세요!.

참고 문헌 :

캐롤라인 야오 (CMP Books)와의 Qing Li의 임베디드 시스템에 대한 실시간 개념.

Andrew Tanenbaum (Pearson Education International)의 현대 운영 체제 (3 차)

-Jeffrey Richter (Microsoft Programming Series)의 Microsoft Windows 용 프로그래밍 응용 프로그램 (4 번째).

또한 https://stackoverflow.com/a/24586803/3163691 을 살펴볼 수 있습니다.


답변

대부분의 문제는 (i) 단지 잠금, (ii) 단지 세마포어, 또는 (iii) 둘의 조합을 사용하여 해결할 수 있습니다! 아시다시피, 경쟁 조건을 방지하고 , 운영 acquire()/ release()운영하고, 0 개 이상의 스레드가 차단 / 의심되는 원인이됩니다. 실제로 중요한 차이점은 잠금 및 잠금 해제 방법 에만 있습니다 .

  • 로크 (또는 뮤텍스 ) 두 상태 (0 또는 1)을 갖는다. 잠금을 해제 하거나 잠글 수 있습니다 . 한 번에 하나의 스레드 만 중요한 섹션에 들어가도록하는 데 자주 사용됩니다.
  • 세마포어가 많은 상태가 (0, 1, 2, …). 그것은 수 로크 (상태 0) 또는 잠금 해제 (3, 2, 1 상태, …). 일부 자원의 단위 수가 특정 값에 도달하지 않았거나 그 값까지 카운트하거나 그 값까지 카운트하여 하나의 스레드 만 중요한 섹션에 정확하게 들어가도록하기 위해 하나 이상의 세마포어가 함께 사용되는 경우가 종종 있습니다. ).

두 잠금 / 세마포 모두에 acquire()대해 기본 요소가 상태 0 인 동안 호출하려고 하면 호출 스레드가 일시 중단됩니다. 잠금의 경우-잠금을 확보하려는 시도가 상태 1에 있습니다. 세마포어의 경우 {1, 2, 3, …} 상태에서 잠금을 획득하려는 시도가 성공했습니다.

상태가 0 인 잠금의 경우 , 이전에 호출했던 동일한 스레드가 acquire()이제 release를 호출하면 릴리스가 성공한 것입니다. 경우 다른 스레드가이 시도 – 그것은 일 (무시 보통 시도 또는 오류가 발생합니다) 무엇으로 구현 / 라이브러리까지입니다. 상태 0의 세마포어의 경우 모든 스레드가 해제를 호출 할 수 있으며 이전에 사용 된 스레드가 세마포어를 상태 0에 놓기 위해 획득 한 스레드에 관계없이 성공합니다.

앞의 논의에서 잠금에는 소유자 (방출을 호출 할 수있는 유일한 스레드가 소유자 임) 라는 개념이 있지만 세마포어에는 소유자가 없습니다 (모든 스레드가 세마포어에서 릴리스를 호출 할 수 있음).


혼동을 일으키는 원인은 실제로 는 이러한 높은 수준의 정의에 많은 변형 이 있다는 것입니다.

고려해야 할 중요한 변형 :

  • 뭐라고를한다 acquire()/ release()호출? – [다름 대규모 ]
  • 잠금 / 세마포어가 “대기열”또는 “세트”를 사용하여 대기중인 스레드를 기억합니까?
  • 잠금 / 세마포어를 다른 프로세스의 스레드와 공유 할 수 있습니까?
  • 자물쇠가 “재진입”입니까? -[보통 예].
  • 자물쇠가 “차단 / 비 차단”입니까? -[일반적으로 비 차단은 차단 잠금 (일명 스핀 잠금)으로 인해 통화 중 대기]로 사용됩니다.
  • 작업이 “원자”인지 어떻게 확인합니까?

이것은 책 / 강사 / 언어 / 도서관 / 환경에 따라 다릅니다.
다음은 일부 언어가 이러한 세부 사항에 응답하는 방법에 대한 빠른 둘러보기입니다.


C, C ++ ( pthreads )

  • 뮤텍스 를 통해 구현된다 pthread_mutex_t. 기본적으로 다른 프로세스와 공유 할 수 PTHREAD_PROCESS_PRIVATE없지만 mutex에는 pshared 라는 속성이 있습니다 . 설정되면 뮤텍스가 프로세스간에 공유됩니다 ( PTHREAD_PROCESS_SHARED).
  • 잠금 뮤텍스와 같은 것입니다.
  • 세마포어 를 통해 구현된다 sem_t. 뮤텍스와 유사하게, 세마포어는 많은 프로세스의 threasd간에 공유되거나 하나의 단일 프로세스 스레드에 대해 비공개로 유지 될 수 있습니다. 이는에 제공된 pshared 인수 에 따라 다릅니다 sem_init.

파이썬 ( threading.py )

  • 잠금 ( threading.RLock) 대부분 C / C ++과 동일 pthread_mutex_t들. 둘 다 재진입 입니다. 이는 잠금 된 동일한 스레드에 의해서만 잠금 해제 될 수 있음을 의미합니다. 이 경우입니다 sem_t세마포어, threading.Semaphore세마포어와 theading.Lock잠금 장치가 재진입하지 – 그것은의 경우에 대한 모든 스레드가 세마포어 아래 / 잠금을 해제 수행 할 수 있습니다.
  • 뮤텍스 잠금 (용어 파이썬 자주 사용되지 않음)과 동일하다.
  • 세마포어 ( threading.Semaphore) 대부분 동일하다 sem_t. 에 있지만 sem_t, 스레드 ID의 큐는이 잠겨있는 동안을 고정 할 때 스레드가 차단되었다 순서를 기억하는 데 사용됩니다. 스레드가 세마포어를 잠금 해제 하면 큐 의 첫 번째 스레드 (있는 경우)가 새 소유자로 선택됩니다. 스레드 ID가 큐에서 제거되고 세마포어가 다시 잠 깁니다. 그러나을 threading.Semaphore사용하면 대기열 대신 세트가 사용되므로 스레드가 차단 된 순서는 저장되지 않습니다 . 세트의 모든 스레드가 다음 소유자로 선택 될 수 있습니다.

자바 ( java.util.concurrent )

  • 잠금 ( java.util.concurrent.ReentrantLock) 대부분 C / C ++와 동일한 pthread_mutex_t의, 파이썬의 threading.RLock그것도 재진입 잠금을 구현하는 것이있다. JVM이 중개자 역할을하기 때문에 Java에서 프로세스 간 잠금 공유가 더 어렵습니다. 스레드가 잠금을 잠금 해제하려고 시도하면 소유하지 않은 것 IllegalMonitorStateException입니다.
  • 뮤텍스 잠금 (용어가 자바에서 자주 사용되지 않음)과 동일합니다.
  • 세마포어 ( java.util.concurrent.Semaphore) 대부분과 동일 sem_t하고 threading.Semaphore. Java 세마포어의 생성자 는 대기중인 스레드를 저장하기 위해 세트 (false) 또는 큐 (true)를 사용할지 여부를 제어 하는 공정성 부울 매개 변수를 승인 합니다.

이론적으로 세마포어는 종종 논의되지만 실제로 세마포어는 그다지 많이 사용되지 않습니다. 세마포어는 하나의 정수 상태 만 유지 하므로 종종 융통성이 없어서 한 번에 많은 것이 필요하므로 코드 이해가 어려워집니다. 또한 어떤 스레드가 세마포어를 해제 할 수 있다는 사실 은 때때로 바람직하지 않습니다. “조건 변수”및 “모니터”와 같은 더 많은 객체 지향 / 고급 동기화 기본 요소 / 추상화가 대신 사용됩니다.


답변

John Kopplin의 멀티 스레딩 자습서 를 살펴보십시오 .

스레드 간 동기화 섹션 에서 이벤트, 잠금, 뮤텍스, 세마포어, 대기 타이머 간의 차이점을 설명합니다.

뮤텍스는 공유 자원에 대한 상호 배타적 인 액세스를 조정하는 스레드를 가능하게 한 번에 하나의 스레드가 소유 할 수있다

중요 섹션 개체 는 단일 프로세스의 스레드에서만 중요 섹션 개체를 사용할 수 있다는 점을 제외하고 뮤텍스 개체와 유사한 동기화를 제공합니다.

뮤텍스크리티컬 섹션의 또 다른 차이점 은 현재 크리티컬 섹션 객체가 다른 스레드에 의해 소유 된
EnterCriticalSection()경우 소유권을 무기한으로 기다리는 반면
WaitForSingleObject()뮤텍스와 함께 사용되는 경우 시간 초과를 지정할 수 있다는 것입니다

세마포어 동시에 공유 자원에 액세스하는 스레드의 수를 제한하는, 제로 카운트 사이의 약간의 최대 값을 유지한다.


답변

나는 그것을 예제로 다루려고 노력할 것이다.

잠금 : 사용하는 한 가지 예는 lock항목 (고유 키가 있어야 함)이 추가 된 공유 사전입니다.
잠금은 한 스레드가 사전에있는 항목을 검사하는 코드 메커니즘에 들어 가지 않고 다른 스레드 (중요 섹션에 있음)가 이미이 검사를 통과하여 항목을 추가하고 있는지 확인합니다. 다른 스레드가 잠긴 코드를 입력하려고하면 객체가 해제 될 때까지 기다립니다 (차단됨).

private static readonly Object obj = new Object();

lock (obj) //after object is locked no thread can come in and insert item into dictionary on a different thread right before other thread passed the check...
{
    if (!sharedDict.ContainsKey(key))
    {
        sharedDict.Add(item);
    }
}

세마포어 :
연결 풀이 있다고 가정하면 단일 스레드가 세마포어가 연결될 때까지 대기하여 풀에 하나의 요소를 예약 할 수 있습니다. 그런 다음 연결을 사용하고 작업이 완료되면 세마포어를 해제하여 연결을 해제합니다.

내가 좋아하는 코드 예제는 @Patric이 제공 한 경비원 중 하나입니다 .

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TheNightclub
{
    public class Program
    {
        public static Semaphore Bouncer { get; set; }

        public static void Main(string[] args)
        {
            // Create the semaphore with 3 slots, where 3 are available.
            Bouncer = new Semaphore(3, 3);

            // Open the nightclub.
            OpenNightclub();
        }

        public static void OpenNightclub()
        {
            for (int i = 1; i <= 50; i++)
            {
                // Let each guest enter on an own thread.
                Thread thread = new Thread(new ParameterizedThreadStart(Guest));
                thread.Start(i);
            }
        }

        public static void Guest(object args)
        {
            // Wait to enter the nightclub (a semaphore to be released).
            Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
            Bouncer.WaitOne();

            // Do some dancing.
            Console.WriteLine("Guest {0} is doing some dancing.", args);
            Thread.Sleep(500);

            // Let one guest out (release one semaphore).
            Console.WriteLine("Guest {0} is leaving the nightclub.", args);
            Bouncer.Release(1);
        }
    }
}

뮤텍스 (Mutex) 그것은 거의 Semaphore(1,1)전 세계적으로 많이 사용됩니다 lock. Mutex전역 적으로 액세스 가능한 목록에서 노드를 삭제할 때 전역을 사용 합니다 (마지막으로 노드를 삭제하는 동안 다른 스레드가 수행하려는 작업). 당신이 취득하면 Mutex다른 스레드의 시도가 동일하게 획득 할 경우 Mutex이를 획득 한 같은 스레드까지 잠을 넣어지게된다 Mutex출시를.

글로벌 뮤텍스를 만드는 좋은 예는 @deepee입니다.

class SingleGlobalInstance : IDisposable
{
    public bool hasHandle = false;
    Mutex mutex;

    private void InitMutex()
    {
        string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value.ToString();
        string mutexId = string.Format("Global\\{{{0}}}", appGuid);
        mutex = new Mutex(false, mutexId);

        var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
        var securitySettings = new MutexSecurity();
        securitySettings.AddAccessRule(allowEveryoneRule);
        mutex.SetAccessControl(securitySettings);
    }

    public SingleGlobalInstance(int timeOut)
    {
        InitMutex();
        try
        {
            if(timeOut < 0)
                hasHandle = mutex.WaitOne(Timeout.Infinite, false);
            else
                hasHandle = mutex.WaitOne(timeOut, false);

            if (hasHandle == false)
                throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");
        }
        catch (AbandonedMutexException)
        {
            hasHandle = true;
        }
    }


    public void Dispose()
    {
        if (mutex != null)
        {
            if (hasHandle)
                mutex.ReleaseMutex();
            mutex.Dispose();
        }
    }
}

다음과 같이 사용하십시오.

using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock
{
    //Only 1 of these runs at a time
    GlobalNodeList.Remove(node)
}

시간이 절약되기를 바랍니다.


답변

Wikipedia에는 세마포어와 뮤텍스차이점 에 대한 훌륭한 섹션이 있습니다 .

뮤텍스는 본질적으로 이진 세마포어와 동일하며 때로는 동일한 기본 구현을 사용합니다. 그들 사이의 차이점은 다음과 같습니다.

뮤텍스에는 소유자라는 개념이 있는데, 뮤텍스를 잠그는 프로세스입니다. 뮤텍스를 잠근 프로세스 만 잠금을 해제 할 수 있습니다. 반대로 세마포어에는 소유자 개념이 없습니다. 모든 프로세스는 세마포어를 잠금 해제 할 수 있습니다.

세마포어와 달리 뮤텍스는 우선 순위 반전 안전을 제공합니다. 뮤텍스는 현재 소유자를 알고 있기 때문에 우선 순위가 높은 작업이 뮤텍스에서 대기하기 시작할 때마다 소유자의 우선 순위를 높이는 것이 가능합니다.

뮤텍스는 뮤텍스를 유지하는 프로세스를 실수로 삭제할 수없는 삭제 안전성을 제공합니다. 세마포어는 이것을 제공하지 않습니다.


답변

내 이해는 뮤텍스가 단일 프로세스 내에서만 사용되지만 많은 스레드에서 사용되는 반면 세마포어는 여러 프로세스 및 해당 스레드 세트에서 사용될 수 있다는 것입니다.

또한 뮤텍스는 이진 (잠금 또는 잠금 해제) 인 반면, 세마포어는 계산 개념 또는 둘 이상의 잠금 및 잠금 해제 요청 큐를 갖습니다.

누군가 내 설명을 확인할 수 있습니까? 저는 Linux, 특히 커널 2.6.32를 사용하는 RHEL (Red Hat Enterprise Linux) 버전 6의 맥락에서 말하고 있습니다.