인프런 커뮤니티 질문&답변

녕나님의 프로필 이미지

작성한 질문수

기출로 대비하는 개발자 전공면접 [CS 완전정복]

Q. multi process/thread의 동기화 문제를 어떻게 해결하나요? (외 1문제) [Mutex & Semaphore]

Semaphore 질문드립니다

작성

·

562

5

Semaphore 에서는 변수 S개 만큼의 프로세스가 동시에 임계영역에 들어갈 수 있다고 하셨는데, 만약 S=3개의 프로세스가 동시에 임계영역에 동시에 들어가서 counter++ 를 한다면
원했던 counter = 3이 안되고 counter=1 이 되는 동기화 문제가 발생할 수 있는게 맞나요??

Semaphore 는 동시에 여러 프로세스가 임계영역에 들어가게 해주는데 동기화가 어떤 방식으로 해결되는지 이해가 안갑니다 ㅠㅠ

답변 3

5

개발남노씨님의 프로필 이미지
개발남노씨
지식공유자

답변이 늦어 죄송합니다. 질문을 받고 명확한 답변이 떠오르지 않아 semaphore에 대해서 좀 더 깊이 알아보다보니 많이 지체되었습니다. 여러 강의와 책을 참조해보니 다음과 같이 설명드릴 수 있을것 같아요.

일단 제가 설명드렸던 동기화(Synchronization)의 정의를 한번 다시 언급해볼게요. 동시성(concurrency)과 데이터 일관성(data consistency)를 만족시키는 것이 동기화의 목표입니다. 여기서 동시성은 멀티쓰레드가 작동하는 환경이고, 데이터 일관성은 우리가 의도한대로 데이터가 조작되어야 된다는 것입니다. 그래서 counter++를 두 쓰레드가 5번, 5번 진행했다면 counter는 0 → 10으로 변경되어야만 데이터 일관성이 만족되는 것입니다.

하지만 동기화는 데이터 일관성뿐 아니라 thread의 실행에 대한 일관성을 모두 포함한 용어입니다.(thread의 실행 일관성은 없는 용어이며, 제가 이해한 대로 설명드리고자 만든 용어입니다.) thread 실행 일관성이란, 여러 쓰레드간의 실행 순서나, 의도한 대로 기능이 작동하도록 하는 것을 말합니다.

thread 일관성에 대한 예시를 들어보겠습니다. 10개의 char형 데이터를 저장할 수 있는 Buffer가 있는데 1 Thread에서 write 작업(buffer에 데이터 추가)을 하고, 2, Thread에서는 read 작업(buffer에서 데이터 추출)하는 작업을 동시에(concurrent) 진행한다고 가정해 보겠습니다.

1Thread는 A,B,C,D,E,F를 buffer에 차례로 총 6번 write를 하고, 2Thread는 총 6번 read하게 되면 A,B,C,D,E,F를 출력해야만 의도했던 대로 thread가 작동되는 것입니다.(Thread의 일관성을 보장해야한다.) 하지만 다음과 같은 예시를 보면 의도했던 대로 작동하지 않는 것을 보실 수 있습니다.

1Thread: write(buffer, ‘A’)

            2Thread : Read(buffer) ⇒ ‘A’

1Thread: write(buffer, ‘B’)

1Thread: write(buffer, ‘C’)

            2Thread : Read(buffer) ⇒ ‘B’

1Thread: write(buffer, ‘D’)

            2Thread : Read(buffer) ⇒ ‘C’

            2Thread : Read(buffer) ⇒ ‘D’

            2Thread : Read(buffer) ⇒ NULL

1Thread: write(buffer, ‘E’)

1Thread: write(buffer, ‘F’)

            2Thread : Read(buffer) ⇒ ‘E’

결국 2Thread는 F까지 읽기를 의도하여 작성되었는데, 의도했던대로 F까지 출력하지 못했습니다(consistency 보장 X). 이런 경우에 semaphore를 사용하여 일관성을 유지할 수 있도록 할 수 있습니다. 어떤 식으로 semaphore가 사용되는지 코드로 보고싶으시다면 아래 링크 (8page, Reader-Writer example)를 확인해보세요~

https://see.stanford.edu/materials/icsppcs107/23-Concurrency-Examples.pdf

 

semaphore가 적용되면 다음과같이 진행이 됩니다.

1Thread: write(buffer, ‘A’)

            2Thread : Read(buffer) ⇒ ‘A’

1Thread: write(buffer, ‘B’)

1Thread: write(buffer, ‘C’)

            2Thread : Read(buffer) ⇒ ‘B’

1Thread: write(buffer, ‘D’)

            2Thread : Read(buffer) ⇒ ‘C’

            2Thread : Read(buffer) ⇒ ‘D’

            2Thread : Read(buffer) ⇒ semaphore_wait() ⇒ semaphore -= 1

1Thread: write(buffer, ‘E’) ⇒ semaphore_signal() ⇒ semaphore += 1 ⇒ 2Thread : Read(buffer) ⇒ ‘E’

1Thread: write(buffer, ‘F’)

            2Thread : Read(buffer) ⇒ ‘F’

 

 

 

 

한편, 다음은 동시성에 대한 udemy강의 (https://www.udemy.com/course/multithreading_parta/)에서 참조한 내용입니다.

  • Critical Section에 여러 thread가 동시에 들어가면 in-consistent(invariant problem) 발생하는거 아니냐?
  • NO! 아니다.  semaphore으로 보호받고 있는 Critical Section에는 몇 가지 특징(가정)이 전제되어 있다. 그것은 여러개의 thread가 동시에 실행되어도 inconsistent 문제를 유발하지 않는 상황이여야 한다는 것이다.

 

 결론은 제가 들었던 예시인 counter는 counting semaphore에 대한 예시로 부적절했습니다. 그래서 녕나님께서 혼란이 오신 것 같습니다. 왜냐하면 counter 예시는 여러 쓰레드가 동시에 CS안에서 작동하면 inconsistency 문제를 발생하게 되기 때문입니다.

언급해주신 다중 공유 자원(a shared resources with multiple instances)를 잘 이해하지 못해서 일단 제가 설명을 쭉드렸는데, 혹시 납득이 되셨나요?? 또 다른 의견 있으시면 얼마든지 말씀해주세요. 납득되지 않는 내용이 있다면 저도 더 찾아보고 의견 나누면 정말 좋을 것 같습니다. 좋은 질문 덕에 저도 더 알아갑니다. 감사합니다.

1

개발남노씨님의 프로필 이미지
개발남노씨
지식공유자

저희 강의에서는 동기화(Synchronization)를 상호배제(mutex)관점에서만 말씀드렸습니다. 하지만 더 넓은 범위의 동기화란 상호배제 뿐 아니라 여러 thread간의 실행 순서를 정해 주는 것도 포함됩니다. 실행순서를 정해주는 동기화를 하기 위해 조건변수(Conditional Variables)을 사용합니다.

semaphore를 활용하면 lock을 사용한 mutex와 같이 상호배제를 구현할 수 있고, 또 조건변수의 역할을 대신할 수 도 있습니다. binary semaphore를 통해 lock으로 사용하여 임계영역을 만드는 것은 semaphore의 한 역할일 뿐이였는데, 제가 설명과정에서 binary가 아닌 semaphore로 임계영역을 설정하는 것처럼 설명드려서 혼동을 드린 것 같습니다.

제가 주로 참조한 책은 Operating System Concepts 10th Edition과 운영체제와 정보기술의 원리 입니다. 이 둘의 책에서는 조건변수와 같은 내용이 나와있지 않고, 동기화에 대한 자세한 설명도 기술되어있지 않습니다. 하지만 이 책을 조금 살펴보시면 도움이 되실 수 있을 것 같습니다.

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-cv.pdf

https://pages.cs.wisc.edu/~remzi/OSTEP/threads-sema.pdf

녕나님께서는 정말 내용을 깊이 이해하시고 질문하시는 것 같아요. 저의 학습 스타일이랑 비슷한 점이 많아서 강의 내용 업데이트에 굉장히 도움이 되고 있습니다. 저도 운영체제에 대해 더 깊은 내용을 담아드리고 싶어서 ‘CS 근본강의 series’를 기획하고 있습니다. 감사합니다!!

0

녕나님의 프로필 이미지
녕나
질문자

먼저 친절한 답변 언제나 감사드립니다 (__)
해주신 답변을 조금 정리하자면,

1. semaphore 로도 mutex 의 lock을 binary semaphore 방식으로 구현할 수 있기도 하다. 하지만, counting semaphore를 활용해 다중 공유 자원(a shared resources with multiple instances)에 대한 프로세스들의 접근 순서를 정해줄 수도 있다. 가 맞을까요?  (공유 프린터의 갯수가 3개같은 경우)

2. 따라서 제가 질문 드렸던 count 변수 1개를 여러 프로세스(쓰레드)에서 +1 하는 작업은 애초에 공유 자원이 1개로 취급되어서 counting semaphore 를 적용하는 것이 의미가 없다(?)로 받아들여도 될까요 ??

녕나님의 프로필 이미지

작성한 질문수

질문하기