Mutex : 상호 배제라는 뜻으로 mutual exclusion의 약자이다. 스레드하나가 임계영역에 들어오면 다른 스레드들은 들어오지 못하도록 배제하는 것
mutex 변수를 이용해서 여러 공유 데이터들을 동시에 액세스 하는 문제점을 보호할 수 있다.
mutex변수가 Lock과 같은 개념으로 작동할 수 있다.
즉, Mutex라는것의 기본 개념은 오직 하나의 스레드만 mutex변수(lock)를 소유할 수 있다. 그래서 여러 스레드들이 동시에 액세스 한다면 가장 먼저 요청한 스레드에게만 lock을 주고 다른 스레드들은 대기한다. 그래서 lock을 다시 용하면 lock을 해제해야 한다. 그래야 다음 스레드들이 액세스 할 수 있기 때문이다. 스레드들은 반드시 임계영역에 의해서 보호된 데이터를 액세스 하는 순서를 가져야 한다.(starvation문제를 해결)
그래서 이러한 문제를 해결하기 위해서 동시에 엑세스하지 못하도록 해야 한다.
전역변수를 여러개의 스레드가 액세스 한다면 여러 스레드들이 액세스 하지 못하도록 임계영역으로 만들어줘야 한다. OS에서 제공해 주는 locking메커니즘 system call함수를 이용해서 하자.
이런 식으로 사용하는 것은 프로그래머의 책임이다.(즉, 동기화 작업을 알아서 잘해라)
동기화는 mutex 말고 또 다른 방법이 있다. Condition variables
locking 매커니즘으로 동기화를 하다 보니 또 다른 동기화 요구사항이 생겼다. 그래서 나오게 된 것이 condition variables이다. 조건은 임계영역 안에서 또 다른 동기화가 필요할 때 사용한다.
Signal handling and threads
프로세스안에 있는 모든 스레드들은 프로세스의 시그널 핸들러를 공유한다. 각각의 스레드들은 각각의 signal mask를 가질 수 있다. 다중 프로세스에서 시그널이 왔을 때 이 시그널은 어떤 스레드가 받아야 할까에 관한 delivery 메커니즘에 따라서 전달되는 방식을 3가지로 나눌 수 있다.
Asynchronous : 시그널 마스크로 막지 않은(unblock한) 스레드에게 전달되는 경우, 그래서 받고자 하는 시그널이 여러 개면 여러 개로 시그널이 전달된다.
Synchronous : 동기식으로 전달하는 방식으로 그 시그널을 발생시킨 스레드에게 시그널을 전달하는 방식이다.
Directed : 누군가가 타깃시그널을 지정한다면 그 특정 스레드에게 전달되어야한다(이미 시그널 안에 목적지 스레드가 정해져 있다는 뜻)
다중 스레드가 존재하는 프로세스에서 시그널 핸들링을 해야할필요가 있을 때 아래의 예제를 이용해서 처리하자.
Readers and writers
mutex lock과 read-write lock을 사용하는 것을 비교하면 read-write lock을 쓰는 것이 오버헤드가 더 있을 수 있다. 왜냐하면 read용인지 write용인지에 따른 부가적인 처리가 필요하기 때문이다. 반면에 read 오퍼레이션만 수행하는 스레드가 lock을 요청한다면 mutex보다 좀 더 유연하게 동시에 공유변수를 액세스 할 수 있도록 하면서 퍼포먼스를 향상할 수 있다.
A strerror_r omplementation
strerror()
이 함수는 thread safe하지 못해서 충돌 문제가 발생했었다. 그래서 보호하기 위해서 mutex lock을 이용해서 안전하게 호출할 수 있도록 할 수 있다. 같은 방법으로 perror도 안전하게 만들 수 있다. 그리고 이 두 함수는 thread safe 하지도 않고 async-signal safe 하지도 않다. 즉, 시그널 핸들러 안에서는 호출하면 안 되는 함수이다. 그래서 이 함수들을 async-signal safe 하게 만들기 위해서 이 함수가 수행되는 동안 시그널을 잠시 block 시킨다. 이렇게 하기 위해서 sigpromask를 이용한다.
Deadlock
스레드가 mutex lock을 갖고있는 상황에서 또 같은 변수에 관해 mutex lock을 요청하면 deadlock에 빠지게 된다. 또한 lock을 가진 스레드가 임계영역에서 작업을 하다가 에러를 만나는 경우에 에러메시지를 출력하고 리턴해버리는 경우가 에러핸들링 루틴에 많이 사용이 된다. 이때 개발자들은 unlock을 하고 리턴을 해야 하는데 lock을 갖고 있는 채로 리턴을 하는 경우가 있다. 이런 경우에는 다른 스레드들은 계속 기다리는 deadlock상황이 발생할 수 있다.
결론은 다중스레드로 작성을 하면 발생할 수 있는 deadlock 문제를 포함해서 발생할 문제를 분석해서 잘 사용하자.