세마포어는 다중 스레딩 문제를 해결하는 데 자주 사용되는 프로그래밍 개념입니다. 커뮤니티에 대한 나의 질문 :
세마포 란 무엇이며 어떻게 사용합니까?
답변
나이트 클럽에서 세마포어를 경비원으로 생각하십시오. 클럽에는 한 번에 허용 된 인원이 있습니다. 클럽이 가득 차면 아무도 입장 할 수 없지만 한 사람이 떠나면 다른 사람이 입장 할 수 있습니다.
특정 리소스에 대한 소비자 수를 제한하는 방법 일뿐입니다. 예를 들어, 응용 프로그램의 데이터베이스에 대한 동시 호출 수를 제한합니다.
다음은 C #에서 매우 교육적인 예입니다.
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);
}
}
}
답변
마이클 바 (Michael Barr)가 해석 한 뮤텍스와 세마포어 (Mutexes and Semaphores) 라는 기사 는 뮤텍스와 세마포어 를 어떻게 다르게 만드는지, 언제 사용해야하는지와 사용하지 않아야 할 때에 대한 짧은 소개입니다. 여기서 몇 가지 주요 단락을 발췌했습니다.
핵심은 공유 리소스를 보호하기 위해 뮤텍스를 사용해야하고 시그널링에는 세마포어를 사용해야한다는 것입니다. 일반적으로 공유 리소스를 보호하기 위해 세마포어를 사용하거나 시그널링을위한 뮤텍스를 사용해서는 안됩니다. 예를 들어 공유 자원을 보호하기 위해 세마포어를 사용한다는 점에서 경비원 비유와 관련된 문제가 있습니다. 이러한 방식으로 사용할 수는 있지만 버그를 진단하기가 어려울 수 있습니다.
뮤텍스와 세마포어는 구현 방식이 유사하지만 항상 다르게 사용해야합니다.
맨 위에 제기 된 질문에 대한 가장 일반적인 (그러나 그럼에도 불구하고 잘못된) 대답은 뮤텍스와 세마포어가 매우 유사하다는 것입니다. 단, 세마포어가 1보다 많을 수 있다는 점만 다릅니다. 거의 모든 엔지니어는 뮤텍스가 중요한 코드 섹션 내에서 상호 배제를 보장함으로써 공유 리소스를 보호하는 데 사용되는 이진 플래그임을 제대로 이해하는 것 같습니다. 그러나 “카운팅 세마포어”를 사용하는 방법을 확장하라는 요청을 받았을 때 대부분의 엔지니어는 자신의 신뢰도만으로도 여러 등가 자원을 보호하는 데 사용된다는 교과서 의견의 일부를 표현합니다.
…
이 시점에서 화장실 키를 공유 리소스를 보호하는 욕실이라는 아이디어를 사용하여 흥미로운 비유를합니다. 상점에 단일 욕실이있는 경우 단일 자원만으로도 해당 자원을 보호하고 여러 사람이 동시에 사용할 수 없게됩니다.
욕실이 여러 개인 경우 욕실을 똑같이 키우고 여러 개의 키를 만들고 싶은 유혹이있을 수 있습니다. 일단 열쇠가 있으면 실제로 어떤 화장실이 있는지 알 수 없으며이 경로를 따라 가면 뮤텍스를 사용하여 정보를 제공하고 이미 차지한 화장실을 가져 가지 않을 것입니다. .
세마포어는 본질적으로 동일한 리소스를 보호하기위한 잘못된 도구이지만 많은 사람들이이를 생각하고 사용합니다. 경비원의 비유는 분명히 다릅니다. 동일한 유형의 리소스가 여러 개가 아니라 여러 명의 동시 사용자를 허용 할 수있는 리소스가 하나 있습니다. 나는 그러한 상황에서 세마포어를 사용할 수 있다고 생각하지만 실제로는 비유가 실제로 실제 상황에서 거의 존재하지 않습니다. 더 자주 같은 유형의 여러 가지가 있지만 여전히 화장실과 같은 개별 리소스가있을 수는 없습니다. 이 방법.
…
세마포어를 올바르게 사용하려면 한 작업에서 다른 작업으로 신호를 보냅니다. 뮤텍스는 보호되는 공유 리소스를 사용하는 각 작업에 의해 항상 순서대로 가져와 해제됩니다. 대조적으로, 세마포어를 사용하는 작업은 신호 또는 대기 중 하나가 아닌 신호입니다. 예를 들어, 작업 1은 “전원”버튼을 눌렀을 때 특정 세마포를 게시 (즉, 신호 또는 증분)하는 코드를 포함 할 수 있고 디스플레이를 깨우는 작업 2는 동일한 세마포어에 종속됩니다. 이 시나리오에서 하나의 작업은 이벤트 신호의 생성자입니다. 다른 소비자.
…
여기서 뮤텍스가 실시간 운영 체제를 나쁜 방식으로 방해하여 리소스 공유로 인해 더 중요한 작업보다 덜 중요한 작업이 실행될 수있는 우선 순위 반전이 발생한다는 중요한 점이 있습니다. 즉, 우선 순위가 낮은 작업이 뮤텍스를 사용하여 리소스 A를 잡고 B를 잡으려고 시도하지만 B를 사용할 수 없기 때문에 일시 중지됩니다. 기다리는 동안 우선 순위가 높은 작업이 필요하고 A가 필요하지만 이미 묶여 있으며 B를 기다리고 있기 때문에 실행되지 않는 프로세스에 의해 해결됩니다. 해결 방법에는 여러 가지가 있지만 가장 자주 해결됩니다. 뮤텍스 및 작업 관리자를 변경하여 이 경우 뮤텍스는 이진 세마포어보다 훨씬 더 복잡합니다.
…
뮤텍스와 세마포어 사이의 광범위한 현대 혼란의 원인은 Djikstra의 1974 년 세마포어 (자본 “S”)의 발명으로 거슬러 올라가는 역사가 있습니다. 그 이전에는 컴퓨터 과학자들에게 알려진 인터럽트 안전 작업 동기화 및 신호 메커니즘 중 어느 것도 3 개 이상의 작업에 효율적으로 확장 할 수 없었습니다. Dijkstra의 혁신적이고 안전하고 확장 가능한 세마포어는 중요한 섹션 보호 및 신호 처리에 모두 적용되었습니다. 그래서 혼란이 시작되었습니다.
그러나 우선 순위 기반 선점 형 RTOS (예 : VRTX, ca. 1980)가 등장한 후 RMA를 설정하는 학술 논문 및 우선 순위 반전으로 인한 문제 및 우선 순위에 관한 논문이 발표 된 후 운영 체제 개발자에게 분명해졌습니다. 1990 년의 상속 프로토콜, 3 뮤텍스는 이진 카운터를 갖는 단순한 세마포 이상이어야한다는 것이 명백 해졌다.
뮤텍스 : 리소스 공유
세마포어 : 신호
부작용을 신중하게 고려하지 않고 다른 것을 사용하지 마십시오.
답변
Mutex : 리소스에 대한 독점 멤버 액세스
세마포어 : 리소스에 대한 n- 멤버 액세스
즉, 뮤텍스를 사용하여 카운터, 파일, 데이터베이스 등에 대한 액세스를 동기화 할 수 있습니다.
Sempahore는 동일한 작업을 수행 할 수 있지만 고정 된 수의 동시 발신자를 지원합니다. 예를 들어, 데이터베이스 스레드를 세마포어 (3)로 감싸서 멀티 스레드 앱이 최대 3 개의 동시 연결로 데이터베이스에 도달하도록 할 수 있습니다. 세 슬롯 중 하나가 열릴 때까지 모든 시도가 차단됩니다. 순진한 스로틀 링과 같은 작업을 정말 쉽고 쉽습니다.
답변
3 (총 수용 할 수있는 택시 고려 후방 ) +2 ( 앞쪽 드라이버 포함) 명. 따라서 semaphore
한 번에 5 명만 차 안에 실을 수 있습니다. 그리고 mutex
자동차의 한 좌석에 한 사람 만 허용합니다.
따라서 Mutex
( OS 스레드와 같은) 리소스에 대한 독점 액세스를 허용 하는 동시에 a Semaphore
는 한 번 에 n 개의 리소스에 대한 액세스를 허용 하는 것입니다.
답변
@ 크레이그 :
세마포어는 리소스를 잠그는 방법으로, 코드가 실행되는 동안이 코드 만 해당 리소스에 액세스 할 수 있습니다. 이렇게하면 두 스레드가 동시에 리소스에 액세스하지 못하게되므로 문제가 발생할 수 있습니다.
이것은 하나의 스레드에만 국한되지 않습니다. 고정 된 수의 스레드가 리소스에 액세스 할 수 있도록 세마포를 구성 할 수 있습니다.
답변
세마포는 … 세마포어로도 사용할 수 있습니다. 예를 들어 큐에 데이터를 큐에 넣는 프로세스가 여러 개이고 큐에서 데이터를 소비하는 작업이 하나만있는 경우 소비하는 작업이 사용 가능한 데이터에 대해 큐를 지속적으로 폴링하지 않게하려면 세마포어를 사용할 수 있습니다.
여기서 세마포어는 배제 메커니즘이 아니라 시그널링 메커니즘으로 사용된다. 소비 작업이 세마포어를 기다리고 있습니다 생산 작업이 세마포어에 게시되고 있습니다.
이렇게하면 대기열에서 빼낼 데이터가있을 때만 소비 작업이 실행됩니다
답변
동시 프로그램을 구축하기 위해서는 동기화와 상호 배제라는 두 가지 필수 개념이 있습니다. 이 두 가지 유형의 잠금 (세마포가 일반적으로 일종의 잠금 메커니즘)이 동기화 및 상호 배제를 달성하는 데 어떻게 도움이되는지 살펴 보겠습니다.
세마포어는 동기화와 상호 배제를 구현하여 동시성을 달성하는 데 도움이되는 프로그래밍 구조입니다. 세마포어는 이진과 계산의 두 가지 유형입니다.
세마포어에는 카운터와 특정 리소스에 액세스하기 위해 대기중인 작업 목록의 두 부분이 있습니다. 세마포어는 두 가지 작업을 수행합니다. 대기 (P) [잠금 획득과 유사] 및 릴리스 (V) [잠금 해제와 유사] – 세마포어에서 수행 할 수있는 유일한 두 작업입니다. 이진 세마포어에서 카운터는 논리적으로 0과 1 사이입니다. 두 개의 값 (열림 / 닫힘)을 가진 잠금과 비슷하다고 생각할 수 있습니다. 카운팅 세마포어에는 count 값이 여러 개 있습니다.
이해해야 할 것은 세마포 카운터가 차단할 필요가없는 작업의 수를 추적한다는 것입니다. 즉, 진행할 수 있습니다. 작업이 카운터되고 카운터가 0 일 때만 세마포어 목록에 추가됩니다. 따라서 작업을 진행할 수 없으면 P () 루틴의 목록에 작업이 추가되고 V () 루틴을 사용하여 “해제”됩니다.
이제 바이너리 세마포어를 사용하여 동기화 및 상호 배제를 해결하는 방법을 알 수 있습니다. 본질적으로 잠금입니다.
전의. 동기화:
thread A{
semaphore &s; //locks/semaphores are passed by reference! think about why this is so.
A(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
;// some block of code B2
...
}
//thread B{
semaphore &s;
B(semaphore &s): s(s){} //constructor
foo(){
...
...
// some block of code B1
s.V();
..
}
main(){
semaphore s(0); // we start the semaphore at 0 (closed)
A a(s);
B b(s);
}
위의 예에서 B2는 B1이 실행을 완료 한 후에 만 실행할 수 있습니다. 스레드 A가 먼저 실행되고 카운터가 0 (닫힘)이므로 sem.P ()에 도달하고 대기한다고 가정합니다. 스레드 B가 함께 나오고 B1을 완료 한 다음 스레드 A를 해제하여 B2를 완료합니다. 그래서 우리는 동기화를 달성합니다.
이제 이진 세마포어와의 상호 배제를 살펴 보자.
thread mutual_ex{
semaphore &s;
mutual_ex(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
//critical section
s.V();
...
...
s.P();
//critical section
s.V();
...
}
main(){
semaphore s(1);
mutual_ex m1(s);
mutual_ex m2(s);
}
상호 배제도 매우 간단합니다. m1과 m2는 동시에 임계 구역에 들어갈 수 없습니다. 따라서 각 스레드는 동일한 세마포어를 사용하여 두 개의 중요한 섹션에 대한 상호 배제를 제공합니다. 이제 더 큰 동시성을 가질 수 있습니까? 중요한 섹션에 따라 다릅니다. (다른 방법으로 상호 배제를 달성하기 위해 세마포어를 어떻게 사용할 수 있는지 생각해보십시오. 힌트 힌트 : 필자는 반드시 하나의 세마포어 만 사용해야합니까?)
세마포 계산 : 둘 이상의 값을 가진 세마포. 이것이 무엇을 의미하는지 봅시다-하나 이상의 값을 가진 자물쇠 ?? 그래서 열리고 닫히고 … 음. 상호 배제 또는 동기화에서 다단계 잠금은 어떤 용도로 사용됩니까?
두 가지 중 더 쉬운 방법을 보자.
카운팅 세마포어를 사용한 동기화 : 3 번 이후에 실행하려는 # 1과 2의 3 가지 작업이 있다고 가정 해 봅시다. 어떻게 동기화를 설계 하시겠습니까?
thread t1{
...
s.P();
//block of code B1
thread t2{
...
s.P();
//block of code B2
thread t3{
...
//block of code B3
s.V();
s.V();
}
따라서 세마포어가 닫힌 상태로 시작되면 t1 및 t2 블록이 세마포어 목록에 추가되는지 확인하십시오. 그런 다음 중요한 모든 t3가 나오고 사업을 마치고 t1과 t2를 해제합니다. 그들은 어떤 순서로 해방 되었습니까? 세마포어 목록의 구현에 따라 다릅니다. 선입 선출 (FIFO), 특정 우선 순위 등을 기반으로 할 수 있음 (참고 : t1과 t2가 특정 순서로 실행되기를 원하고 세마포어의 구현을 모르는 경우 P와 V를 정렬하는 방법에 대해 생각하십시오)
(발견 : V의 수가 P의 수보다 크면 어떻게됩니까?)
상호 배제 카운팅 세마포어를 사용하여 : 나는 당신이 이것을 위해 자신의 의사 코드를 구성하고 싶습니다 (일을 더 잘 이해하게 만듭니다!) . 이것이 의미하는 것은 N 개의 작업 (또는 원하는 경우 스레드)이 중요 섹션에 들어가 있지만 N + 1 번째 작업은 차단되고 (가장 좋아하는 차단 된 작업 목록에 표시됨) 누군가 V가 세마포어 일 때만 통과됩니다. 적어도 한 번. 따라서 세마포 카운터는 0과 1 사이에서 스윙하는 대신 이제 0과 N 사이로 이동하여 N 작업이 자유롭게 들어가고 나갈 수있게하여 아무도 막지 않습니다!
이제 어리석은 일이 왜 필요합니까? 둘 이상의 사람이 리소스에 액세스하지 못하게하는 상호 배제의 요점이 아닙니까? (힌트 힌트 … 컴퓨터에 항상 하나의 드라이브 만있는 것은 아닙니다.
생각해보기 : 세마포 만 세면 상호 배제가 달성됩니까? 리소스의 인스턴스가 10 개이고 카운팅 세마포어를 통해 10 개의 스레드가 들어 와서 첫 번째 인스턴스를 사용하려고하면 어떻게됩니까?