1

아래 코드가 어떻게 작동하는지 이해하려고합니다. 이것은 제 교수 강의 슬라이드에서 곧장 나옵니다. 이 P()와 V() 함수는 우리가 클래스 (OS161)에서 사용하는 OS에서 세마포어 구현의 일부이다. 내 질문에 대답하기 위해 OS161을 이해해야 할 필요가 있다고 생각합니다. 널리 사용되기 때문에이 질문에 답할 수 있기를 바랍니다.

강의 노트이 코드의 나의 이해 :
X :는 P() 함수를 우리가있는 경우 스레드 콜 P(), 우리는 해제가
2. 검사를 중단

1의 흐름 sem-> count에서 사용할 수있는 리소스
3.a) count가 0이면 우리는 잠들게된다.
3.b!) count! = 0이면 카운트를 감소시키고 호출하는 스레드가 critical 섹션으로 계속하도록 허용
4. 인터럽트 활성화
Y : 스레드 호출 V(), 우리가 비활성화 지금 이제
3.를 잡기 위해 가능한 한 많은 자원이 있음을 암시
2. 증가를 카운터를 인터럽트 V() 함수

1의 흐름 우리는 P()에서 잠을 자려고 보낸 모든 스레드를 깨우려고합니다. 스레드가 중요한 섹션에 대한 잠금을 잡으려고 할 때 충분한 리소스가 없기 때문에 깨어납니다.
인터럽트가 비활성화 된 상태에서 스레드는 어떻게 잠자기 상태가됩니까?

내 문제 :
1. "인터럽트 사용 안 함"섹션이 특정 쓰레드에서 인터럽트를 비활성화합니까? 광고 또는 모든 인터럽트를 비활성화합니까?
2. V() 함수에서 모든 스레드를 깨우면 P() 함수에서 while 루프 내부에서 슬립 된 스레드가 while 루프를 실행하기 시작합니다. 강의에서 그것은 하나의 실이 자물쇠를 잡고 나머지는 잠자 러가는 것을 말합니다. 내 질문은 "sem-> count == 0"조건이 다른 스레드가 아니라 하나만 false로 평가하는 이유입니다.

인터럽트 비활성화 부분이 어떻게 작동하는지 정말로 알고 싶습니다. 이것이 제 첫 질문입니다. 스레드 스케줄러를 중지합니까?, 시스템에서 컨텍스트 전환을 중지합니까?

스레드가 인터럽트 해제로 인해 절전 모드로 전환되는 이유는 무엇입니까? I/O 완료 신호 및 다른 것들을 놓칠 수 있기 때문에 그렇게 위험하지 않습니까?

P(sem) { 
     Disable interrupts; 
     while (sem->count == 0) { 
     thread_sleep(sem); /* current thread 
           will sleep on this sem */ 
     } 
     sem->count--; 
     Enable interrupts; 
    } 
    V(sem) { 
     Disable interrupts; 
     sem->count++; 
     thread_wakeup (sem); /* this will wake 
     up all the threads waiting on this 
        sem. Why wake up all threads? */ 
     Enable interrupts; 
    } 

감사합니다.

답변

5

CPU는 스레드에 대해 아무것도 모르고 있으며, 소프트웨어에서 구현 된 논리적/추상적 개념 일뿐입니다. 그러나 CPU는 인터럽트에 대해 알고 있고, 실제로 존재하며, 어떤 장치에서 들어올 때마다 CPU는 실행중인 모든 실행을 중지하고이 특정 인터럽트를 처리하는 루틴을 실행하기 시작합니다. 일단 완료되면, 루틴은 인터럽트 처리의 완료를 신호하고 CPU는 인터럽트 처리 루틴에 의해 선점 된 것의 실행을 재개합니다.

선매 코드가 스레드에 속한 경우 그렇게하십시오. 그것이 루틴을 처리하는 또 다른 인터럽트라면, 괜찮습니다.

인터럽트 처리 루틴이 시작되기 직전에 CPU는 실행 컨텍스트 (몇 가지 범용 레지스터와 약간의 제어/시스템 레지스터)를 스택이나 다른 곳에 저장하므로 루틴에서이를 사용할 수 있습니다. 자신의 목적을 달성 한 다음 루틴이 끝나면 CPU는 중단 된 코드의 관점에서 아무 일도 일어나지 않은 것처럼 레지스터가 저장된 위치에서 해당 레지스터를 복원합니다. 루틴이 이러한 레지스터를 변경하면 CPU는 인터럽트가 발생하기 전 마지막 실행 시점이 아닌 다른 곳에서 실행을 다시 시작합니다.

그래서, 당신은 인터럽트를 사용하여 다양한 코드, 스레드 또는 무엇을 가지고 있는지간에 실행을 전환 할 수 있습니다. 사실 이것은 정확히 얼마나 많은 스케줄러가 작동하는지입니다. 그들은 타이머로부터 정기적 인 인터럽트를받으며 인터럽트 핸들러에서는 선점 된 코드 (예 : 스레드 A)의 컨텍스트를 메모리에 저장하고 다른 선점 된 코드 (예 : 스레드 B)의 컨텍스트를 메모리에서로드하고 반환함으로써 다른 스레드에서 실행을 계속합니다 .

이러한 타이머 인터럽트를 비활성화하면주기적인 스레드 스케줄링/전환도 비활성화됩니다. 인터럽트는 전체 CPU 및 현재 실행중인 스레드 (또는 그 무엇이든지)에 영향을 미치고 유도로 모든 스레드에 영향을 미칩니다.

알아 들었어?

이제 시스템에 스레드가 있으면 실행할 수있는 스레드가 항상 하나 이상 있습니다. 이것은 CPU가 무엇인가를 실행해야하기 때문에 멈추어 서 스레드가 아무 곳에도 도착할 때까지 기다릴 수 없기 때문입니다 (결국 스레드를 생성하고 실행 가능하게 만들고 실행하는 CPU). 이 목적을 위해 낮은 우선 순위를 가지며 거의 아무것도하지 않는 더미 (또는 너무 가짜 인) 스레드가있어 영원히 반복되며 아마도 CPU에 더 낮은 전력 상태로 전환되거나 인터럽트가 들어올 때까지 중단 될 수 있음을 알립니다 인터럽트는 저전력 모드를 끝내고 코드가 계속 실행되도록합니다.

그래서 세마포어 또는 다른 동기화 프리미티브에서 스레드가 차단되면 스케줄러는 단순히 실행할 다른 스레드를 선택합니다. 모든 스레드가 차단되면 더미 스레드가 선택됩니다.

코드에서 인터럽트는 짧은 시간 동안 비활성화되지만 커널 코드는 다양한 전역 변수 (예 : 차단/대기 및 준비 스레드 목록)를 조작합니다. 그건 정상입니다. 여기서 경쟁 조건을 원하지 않습니다. 인터럽트는 스케줄러가 실행할 다른 스레드를 선택하고 실행을 계속할 때 다시 활성화됩니다.

가 AT-어떤 점 - 현재의 thread가 자고 완료되면 (다른 스레드가 그것을 깨어 나면 예 :), 항상 인터럽트 수 있다는 관찰

:

spl = splhigh(); // disable interrupts 
while (sem->count==0) { 
    thread_sleep(sem); // context switch (to another thread and then back) occurs here 
} 
sem->count--; 
splx(spl); // <-- re-enable interrupts here 

인터럽트를 발생합니다 이러한 방식으로 차단 된 모든 스레드 깨어 났을 때 다시 활성화되어 실행되도록 스케줄러에 의해 선택됩니다.

그냥 생각해보십시오. 위 또는 유사한 코드의 인스턴스가 2 (또는 그 이상) 2 개 이상의 스레드에 있습니다. thread_sleep() 또는 유사한 기능을 입력하면 다른 스레드가 thread_sleep() 또는 이와 유사한 기능을 벗어나서 인터럽트를 다시 활성화합니다.

P()
    thread_sleep()
        mi_switch()
            md_switch()
,319,431,365 :

이 경로를 따라 코드와 의견에 따라              mips_switch는() 세마포어 카운트에 관해서는

, 지금은 더 많은 코드 분석을 할 생각하지 않아요. 누군가 다른 사람이 차임하고 커버하지 않는 한 자신을 알아 내려고 노력해야합니다.