(제 질문에 대한 배경을 먼저 설명합니다. 질문 자체는 맨 아래에 있으며 "질문"은 굵게 표시되어 있습니다).
두 개의 프로세스 A와 B를 예로 들어보겠습니다. A는 조건을 확인하여 조건이 충족되지 않은 것을 발견한 후 슬립/차단 상태로 진입합니다. B는 조건을 만족하고 A를 깨운다. 모든 일이 이 순서대로 일어난다면 아무런 문제가 없습니다.
이제 스케줄러가 다음을 수행하는 경우:
- 확인 조건이 충족되지 않음
- B는 조건을 충족하고 A를 깨운다
- A 절전 모드로 전환/차단
그런 다음 B가 A를 위해 수행한 웨이크업을 잃습니다.
나는 차단 세마포어를 구현하는 과정에서 이 문제에 부딪혔습니다. 이에 대한 솔루션을 제공하는 여러 소스는 다음과 같습니다.
Andrew Tanenbaum, 최신 운영 체제, 4판, 14페이지. 130:
여기서 문제의 본질은 아직 절전 모드로 전환되지 않은 프로세스에 보낸 웨이크업이 손실된다는 것입니다. 아무것도 잃지 않으면 모든 것이 잘 될 것입니다. 빠른 수정은 추가할 규칙을 수정하는 것입니다.기상 대기 비트그림에. 이 비트는 아직 깨어 있는 프로세스에 깨우기가 전송될 때 설정됩니다. 나중에 프로세스가 절전 모드로 전환하려고 할 때 wake-wait 비트가 켜져 있으면 꺼지지만 프로세스는 활성 상태로 유지됩니다. 웨이크업 대기 비트는 웨이크업 신호를 저장하는 저금통입니다. 소비자는 루프가 반복될 때마다 wake-wait 비트를 지웁니다.
이 기사는 Linux Magazine에 게재되었습니다.("Kernel Korner - Sleeping in the Kernel", Linux Journal #137)에서는 다음과 같이 언급합니다.
이 코드는 웨이크업 손실 문제를 방지합니다. 어떻게? 조건을 테스트하기 전에 현재 상태를 TASK_INTERRUPTIBLE로 변경했습니다. 그럼 무엇이 바뀌었나요? 변경 사항은 TASK_INTERRUPTIBLE 또는 TASK_UNINTERRUPTIBLE 상태의 프로세스가 wake_up_process를 호출하고 프로세스가 아직 Schedule()을 호출하지 않을 때마다 프로세스 상태가 다시 TASK_RUNNING으로 변경된다는 것입니다.
따라서 위의 예에서 프로세스 B가 list_empty를 확인한 후 언제든지 wakeup을 실행하더라도 A의 상태는 자동으로 TASK_RUNNING으로 변경됩니다. 따라서, Schedule()을 호출하면 앞서 설명한 것처럼 프로세스 A가 절전 모드로 전환되지 않고 일정 기간 동안만 예약됩니다. 따라서 wakeup은 더 이상 손실되지 않습니다.
내가 이해하는 바에 따르면 이는 기본적으로 "나중에 절전 모드를 해제하면 나중에 절전/차단 호출을 취소할 수 있도록 프로세스를 절전/차단하려는 프로세스로 표시할 수 있습니다"라고 말합니다.
마침내이 유인물아래쪽 몇 단락에는 "다음 의사 코드는 차단 세마포라고 하는 이러한 세마포의 구현을 보여줍니다."에서 세마포를 차단하는 코드가 제공되며 원자 연산 "Release_mutex_and_block(csem.mutex);"을 사용합니다. 그들은 다음과 같이 주장합니다.
P()ing 프로세스는 자동으로 실행 불가능 상태가 되어 뮤텍스를 해제해야 합니다. 웨이크 로스(wake loss)의 위험이 있기 때문이다. release_mutex(xsem.mutex) 및 sleep()이라는 두 가지 다른 작업이 있는 경우를 상상해 보십시오. release_mutex()와 sleep() 사이에 컨텍스트 전환이 발생하면 다른 프로세스가 V() 작업을 수행하고 첫 번째 프로세스를 dequeue_and_wakeup()하려고 시도할 수 있습니다. 불행하게도 첫 번째 프로세스는 아직 잠들지 않았기 때문에 깨우기를 놓치게 됩니다. 대신에 다시 실행되면 즉시 잠자기 상태가 되고 아무도 깨우지 않습니다.
운영 체제는 일반적으로 뮤텍스를 매개변수로 사용하는 sleep() 시스템 호출 형식으로 이러한 지원을 제공합니다. 그런 다음 커널은 뮤텍스를 해제하고 프로세스를 인터럽트 없는(또는 보호되는) 환경에서 절전 모드로 전환할 수 있습니다.
질문:UNIX의 프로세스에는 "잠자기 계획 중입니다" 또는 Tanenbaum이 말했듯이 "깨우기 대기 비트"로 표시하는 방법이 있습니까? 뮤텍스를 원자적으로 해제한 다음 프로세스를 절전 모드로 전환/차단하는 시스템 호출 sleep(mutex)이 있습니까?
분명히 나는 시스템 호출과 일반적인 운영 체제 내부에 익숙하지 않습니다. 내 질문에 명백히 잘못된 가정이나 용어의 오용이 있는 경우 이를 지적해 주시면 감사하겠습니다.
답변1
전통적인 Unixy 솔루션은 대기 프로세스가 읽으려고 시도할 파이프에 바이트를 쓰는 것으로 구성된 "깨우기" 신호를 갖는 것입니다.
(프로세스에 이 기능을 설정하는 데 도움이 될 수 있는 공통 조상이 없는 경우 명명된 파이프를 사용할 수 있습니다.)
그런 다음 대기 프로세스는 select() 시스템 호출(또는 pselect 또는 poll/epoll과 같이 최근에 재설계된 대안 중 하나)을 사용할 수 있습니다.원자적으로"해당 파일 설명자에서 읽을 준비가 될 때까지 기다리십시오"를 수행하십시오. 깨어나면 읽으려고 했던 모든 내용을 읽고 삭제합니다.그 다음에어떤 작업이 준비되었는지 확인하세요.