참고자료
OS 책: “Operating Systems: Three Easy Pieces”
카이스트 권영진 교수님 강의
궁금했던 점
https://velog.io/@bongf/Pintos-1.-Priority-Scheduling 여기 작성했던 부분
- pintOS에서는 이렇게 condition varaible이 구현되어 있다.
- connd에 접근하는 작업은 lock으로 보호한다.
- connd에는 sema_elem의 elem, 즉, sema_elem들이 줄 서게 되는데, sema_elem은 자신이 줄 설 때 사용할 elem과 semaphore로 구성된다.
- semaphore에는 value와 waiters가 있어서 줄 설 수 있는데 (cond_waiter에 들어가는 sema_elem의 seam는 )여기에는 semaphore의 연산에 한 명만 넣을 수 있도록 (sema_elem을 생성할 때 sema도 하나 만들고 block, 깨어나면서 cond_waiter에서 아예 pop 하여 쎄마를 깨우고 버림) 제한한다.
- 굳이 왜 thread로 줄 세우지 않고(readay-list)처럼 sema로 한 번 감싸서 줄세우는 지가 궁금했다.
해결
https://pages.cs.wisc.edu/~remzi/OSTEP/threads-sema.pdf
요약
: Semphore의 시그널링에 대한 순서를 주는 기능을 쓰기 위해서.
- Semaphore는 초기값을 무엇으로 하냐에 따라서 lock와 condtition variable로 쓸 수 있다. (출처 책)
lock
Semaphore의 초기값을 1으로 하면 lock으로 쓸 수 있다.
ordering 주기
-
Semaphore의 초기값을 0으로 하면 순서가 있는 시그널링 기능으로 쓸 수 있다.
-
완벽히 condition variable과 같다고 할 수는 없지만, condition variable도 먼저 잠든 것이 먼저 깨게 할 수 있다는 점에 착안하면 sema의 초기값을 0으로 초기화하면, 실행 될 순서를 정해줄 수 있다
- 책에서 나온 순서를 정한다는 말은 책에서 나온 말이다. (잘 이해가 가질 않았는데) 초기값을 0으로 하면 먼저 실행한 애는 무조건 잠들게 된다. (자원의 초기값이 0이니까.) 그래서 무조건 잠들고 누군가가 깨워줘야만 활동할 수 있는 상태가 된다. 이런 순서를 정해준 다는 것으로 이해했다.
- 이를 pintOS project2에서 많이 사용했다. 그 한 예로 자식이 죽을 때 부모를 깨워서 자식이 죽음을 알리는데 죽기 직전에 sema_down을 해서 잠들어 버린다. 그렇게 하는 이유는 부모가 자식을 죽이기 직전에 자식의 상태를 확인해야 하기 때문에 아직 자식의 자원이 완전히 해제되면 안되기 때문이다. 그래서 부모는 깨어나서 자식을 죽이고 잠든 자식을 위해 sema_up을 해주면 자식은 깨어나서 완전히 자원이 해제될 수 있게 된다.
-
다시 connd에서 순서가 있는 시그널링 기능을 보면, 여기서 말하는 시그널링 기능은 사실 cond - wait에 들어가는 순간 먼저 어차피 잠들어야 하므로, 자원의 초기값이 0인 세마포어를 이용해서 바로 sema_down() 하면 바로 잠들 수 있도록 하는 것으로 이해했다.
- 그렇게 했을 때 intr_block()(인터럽트 블락)이나 별도의 작업들 없이도 쓰레드를 잠들 수 있게 할 수 있기 때문이다.
쎄마와 lock의 차이 정리
https://www.geeksforgeeks.org/difference-between-spinlock-and-semaphore/
- lock은 busy-wait을 한다.
- sema는 잠들게하고, 깨운다.
- sleep-wake 방식이 훨씬 더 효율적일 수 있지만 교체가 빠른 작업에서는 애를 깨우고 재우는 방식에 대한 비용 때문에 오히려 더 비효율적일 수가 있다.