멀티 쓰레딩에서 데이터를 공유할 때 발생하는 문제
- 멀티 쓰레딩의 장점은 쓰레드들간에 데이터를 쉽게 주고 받을 수 있다는 것
- -> 그러나 여러 쓰레드가 동시에 접근할 때, 정확하게 데이터 값을 가질수 있도록 하는 것은 매우 어려운 문제
- 하나의 쓰레드가 메모리 영역에 대해 확실하게 자신의 영역을 가지고 있는 경우 -> 각자 할당된 데이터 영역을 read, write하므로 문제가 생기지 않음
- 같은 메모리 영역을 동시에 읽고 쓰는 경우?
- ex)웹 서버 : 연결을 요청할 때마다 쓰레드를 만들어냄 -> 쓰레드들은 html파일을 메모리에 캐시형태로 보관 -> 여러개의 쓰레드들이 이 파일을 동시에 읽고 씀 -> 정확한 파일 값을 유지하기 어려워짐
- 몇 명의 client가 접속해 있는지 저장하는 변수가 있다고 가정하고 예제를 확인해보자
- for루프를 돌면서 쓰레드 생성 - 이 경우는 2개의 worker thread
- worker thread는 50000번 만큼 cnt를 +해줌
- thread 1과 2가 있을 때, 두 쓰레드를 동시에 실행시킨다면 각각 50000번씩 총 100000이라는 cnt가 출력되어야 하는데 실제로는 100000보다 작은 수가 출력되는 것을 볼 수 있음
- 이유
- 5만 번씩 반복하는 for문을 기계어로 풀었을 때의 모습
- cnt값을 메모리에서 레지스터로 읽어오는 load연산
- 레지스터의 cnt값을 update하는 부분
- 증가한 cnt값을 다시 메모리로 저장하는 store연산
- 위 세 과정이 한꺼번에 이루어짐(Critical section) -> 다른 무언가가 끼어들면 문제가 발생
- 동시에 수행되는 경우를 보자
- H -> L(cnt에서 레지스터로 값을 불러옴) -> U(+1하는 연산) -> S(더한 값을 다시 메모리에 저장)까지 thread 1 실행
- thread 2가 끼어들어서 H -> L(cnt값을 레지스터로 불러옴) -> U(+1) -> S(저장)
- 이 경우에는 우리가 원하는 결과를 얻을 수 있음
- 또다른 예제를 보자
- 아까와 마찬가지로 thread 1은 U까지 수행함 그러나 저장하기 전에 thread 2가 수행된다면
- L에서 cnt값을 읽어올때 thread 1에서 저장하지 않았으므로 +1을 하기 전인 0을 불러옴
- 불러온 후 thread 1의 값이 저장(S)이 됨
- thread 2가 다시 실행되어 저장까지 되면 그대로 1이 저장이 되는 결과가 나타남
멀티쓰레딩 프로그램의 정확성 보장 방법
- 안전하지 않은 쓰레드들의 수행을 동기화 시켜줌(Synchronize)
- 동시에 수행되어 문제가 발생할 수 있는 부분은 하나의 쓰레드만 수행할 수 있도록 정해줌(mutually exclusive access)
- 정확성을 유지할 수 있도록 충분한 조건을 주어 코딩
- ex)여러가지 기능들 제공
- pthreads : semaphores, Mutexes, and condition variables, Locks and rwrite locks
- Java : Monitors
Mutexes(mutual exclusion)
- special type을 가지는 변수 - pthread_mutex_t, pthread_mutexattr_t
- 어떤 코드의 부분을 한 쓰레드만 수행할 수 있도록 지정해줌
- pthread_mutex_init(2)/destroy(3)
- 첫 번째 pthread_mutex_init : 선언한 mutex 변수를 우리가 원하는 attribute를 가지도록 설정해줌 -> NULL로 설정시 default값이 됨
- 두 번째 : pthread_mutex_t mutex를 선언할 때, 뒤에 매크로인 PTHREAD_MUTEX_INITIALIZER을 써줌
- 다 사용한 후 해제할 경우 pthread_mutex_destroy를 써줘서 해제
- pthread_mutex_lock(2)/unlock(3)
- pthread_mutex_lock : lock을 해주면 critical section으로 지정됨 -> 지정된 후 한 쓰레드가 수행중이라면 다른 쓰레드가 오더라도 동시에 수행하지 못하고 대기상태(suspend)가 되어 기다림
- pthread_mutex_unlock : unlock을 거쳐서 쓰레드가 나가게 되면 대기중이었던 쓰레드가 수행을 시작
- lock과 unlock은 항상 쌍으로 쓰여야함 -> unrock을 하지 않으면 한 쓰레드가 수행 후 다른 쓰레드들은 수행하지 못하게 됨
- pthread_mutex_trylock : 이미 critical section에서 수행중인 쓰레드가 있다면 기다리지 않고 return해버림
- 예제
- for문으로 여러개의 work 쓰레드를 생성
- worker는 cnt를 증가시킴 -> 50000번씩 반복
- mutex를 사용하지 않은 경우 원하는 결과가 나오지 않았으나 lock을 걸고 unlock으로 cnt를 감싸주면 쓰레드 하나가 실행중일때 다른 쓰레드는 대기
- unlock을 통해 한 쓰레드가 나가야지 비로소 대기중인 쓰레드가 수행하므로 원하는 결과값을 얻을 수 있게됨
'임베디드SW공학' 카테고리의 다른 글
[12주차]POSIX Threads(1) (0) | 2018.12.01 |
---|---|
[11주차]시그널과 타이머 (0) | 2018.11.27 |
[10주차]리눅스 시스템 프로그래밍:Processes (0) | 2018.11.19 |
[9주차]시스템 콜 파일(2) - 디렉토리 (0) | 2018.11.17 |
[8주차]리눅스시스템 프로그래밍: File I/O (0) | 2018.11.11 |