좀더 Higher-level에서 소프트웨어를 가지고 critical section을 해결할 방법!
Mutex Locks
열쇠를 가지고 들어갔다가 나올때 이 열쇠를 반납해라
2개의 프로세스
가장 간단한 synchronization 툴
동기화를 위한 가장 간단한 도구
바이너리 세마포어라고 부를 수 있다.
세마포어 값이 0 또는 1을 가지는 이진 세마포어(Binary Semaphore)
임계구역을 보호하고 경쟁 상태(race condition)을 예방한다.
은 임계구역 입장 전 Lock을 얻어야 하고 임계 구역을 나가게 되면 Lock을 해제한다.
Semaphore
가장 보편적임, 편리하고 효과적이다.
n개의 스레드를 다룰 수있다
Monitor
metex와 semaphore의 단점 극복
Liveness
Progress되는것을 보장
상호배제 해결해주면 데드락 해결해준다.
mutex: mutual exclusion
상호배제
critical section을 보호한다. 임계 영역에 들어갈때 열쇠를 줘가지고 이 열쇠를 받고 들어가고 나오면 반납한다. -> race condition을 예방한다.(특정 베리어블, 특정 공유자원 액세스 보호)
critical secition 들어갈때 lock 을 사용하기 위해 acquire하는과정 필요
exit할때 critical section 나갈때 release 반납한다.
entry section -> require lock 으로 바뀜
exit section -> release-lock으로 바뀜
acquire() release() 두 개의 오퍼레이션 제공해주면 된다.
avilable : Boolean variable 이 true면 lock available 하고, false면 lock이 열쇠가 없다.

acquire() : available이 false면 while 계속 돌면서 대기한다. available 얻으면 false로 바꾼다. -> 획득
release() : 다 쓰고 나면 avilable 을 true로 만든다. -> 반납
둘 다 atomic하게 실행되어야함

Busy waiting : 바쁜대기
한 프로세스가 자신의 임계 구역에 있으면, 자신의 임계 구역에 진입하려는 다른 프로세스가 진입 코드를 계속 반복 수행(무한루프)하는 것
어떤 프로세스가 자기 critical section 들어가기 위해무한루프를 돈다.
멀티 프로세싱에서 환경에서 신각한 단점이됨
CPU 코어를 낭비.
예를들어 싱글 CPU 코어에서 not available인동안에 계속돈다.-> 쓸데없이 CPU를 소모함 -> 다른 프로세스가 생산적으로 쓸 수있는 시간을 무한루프돌면서 CPU를 잡아먹느다.
Spinlock
뮤텍스락을 busy waiting하면서 기다리고 있는 락: spinlock
(Busy Waiting) 방식을 이용한 뮤텍스 락의 잠금 유형
프로세스는 lock을 얻을때까지 대기하는 동안 반복문을 반복
프로세스가 쓸데없이 계속 이 락을 대기하면서 기다림
ock을 얻기 위해 대기하는 동안 문맥 교환(Context Switch)가 요구되지 않는다.
멀티코어일땐 유용함 선호됨. 여러 코어들이 busy waiting 하면서 기다리다가 lock이 풀리면 바로 진입할 수있다.
busy waiting = spin lock
원래는wait queue에 있다가 available이 풀려서 ready queue갔다가 실행하고 그러니까 컨텍스트 스위칭을해야함. 근데 busy waiting 하고있으면 바로 컨텍스트스위치되서 사용할 수 있음. -> 시간 세이브
=> 멀티코어 시스템에서선호될때도 있다.
Mutex Locks
#include <stdio.h>
#include <pthread.h>
int sum = 0; // a shared variable
pthread_mutex_t mutex; // mutex 타입 선언
int main()
{
pthread_t tid1, tid2;
pthread_mutex_init(&mutex, NULL); // null로 초기화
pthread_create(&tid1, NULL, counter, NULL); // 두개의 스레드
pthread_create(&tid2, NULL, counter, NULL); // 두개의 스레드
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("sum = %d\n", sum);
}
void *counter(void *param)
{
int k;
for (k = 0; k < 10000; k++) {
/* entry section */
pthread_mutex_lock(&mutex); // lock 획득
/* critical section */
sum++;
/* exit section */
pthread_mutex_unlock(&mutex); // 열쇠 반납
/* remainder section */
}
pthread_exit(0);
}
=> synchronize
mutual exclusion 은 해결 , deadlock, atarvation은 해결 안됨
Semaphore
신호장치, 신호기
두개의 오퍼레이션 필요 : wait() , signal() = P() , V()
wait(S): 전역변수 S 에대해서(일종의 lock) 0보다 작거나 같을동안 --
signal(S): S ++
둘다 atomic 해야됨
S가 10이면 .. while 들어가지않고 .. --감소 / 0이되면 busy waiting
signal 에서 ++증가
=> 여러 열쇠가 있는데 이 10개의 열쇠가 다 0이되면 진입하지못하고 busy waiting
만약 3개의 프린터가 연결되어있다. s를3으로 둔다. 세개가 열쇠를 사용할때마다 감소해서 0이되면 다른 프린터들은 요청 대기

n개의 인스턴스를 가진 자원을 서로 공유할 때 사용
Binary Semaphore
n이 1이면 1 됐다가 0됐다가 함 -> mutex lock 하고 똑같음
Counting Semaphore
n이 무한대로 클 수있다. 여러개의 인스턴스를 가진 자원에 사용
available한 리소스의 갯수 n = s 로 초기화
리소스를 사용하때 wait() 쓰면됨 , 나올때 signal()
s가 0이된 상태 : 모든리소스가 사용되고 있기때문에 이 프로세스 블록
프로세스 P1, P2가 S1, S2를 가지고 있다.
S1 실행하고 S2를 실행하고 싶다. -> s를 0으로 두고 S1 실행하고 signal 실행( ++) 그리고 wait() 하고 S2실행
똑같이 busy waiting 문제 생김
->
wait() 으로 while 상태라면 -> CUP 반납해버리고 waiting queue에 대기하자. 그러다가 다른 프로세스가 signal 호출하면 시그널에있는 오퍼레이션이 waiting queue에 있던 프로세스 wake up 시킨다. -> ready queue
=> busy waiting 해결
semaphore 구조체:
int value -> s
process *list -> 대기하고있는 프로세스 리스트
wait():
value < 0 이면 process를 리스트에 넣고 sleep 시킨다.(wait queue로)
signal():
value ++ 하고 대기 리스트에 있던 프로세스 리스트에서 remove시켜서 wakeup한다.
시그널 받은놈은 레디큐로

binary semaphore
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
int sum = 0; // a shared variable
sem_t sem; // semaphore 선언
int main()
{
pthread_t tid1, tid2;
sem_init(&sem, 0, 1); // s는 1이다.
pthread_create(&tid1, NULL, counter, NULL); // create
pthread_create(&tid2, NULL, counter, NULL); // create
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("sum = %d\n", sum);
}
void *counter(void *param)
{
int k;
for (k = 0; k < 10000; k++) {
/* entry section */
sem_wait(&sem); // P()
/* critical section */
sum++;
/* exit section */
sem_post(&sem); // V()
/* remainder section */
}
pthread_exit(0);
}
=> synchronize 해결, s가 1이니까 mutex에 불과
s 여러개:
int main()
{
pthread_t tid[5]; int i;
sem_init(&sem, 0, 5); // s 5개 초기화
for (i = 0; i < 5; i++) // thread 5개 create
pthread_create(&tid[i], NULL, counter, NULL);
for (i = 0; i < 5; i++)
pthread_join(tid[i], NULL);
printf("sum = %d\n", sum);
}
=> synchronize 해결안됨 , 열쇠를 5명 갖고있으니까 race condition 그대로 발생
예를들어 5개짜리 배열이 있으면 다섯개 스레드가 각각 들어가서 값을 바꾸니까 race condition 발생안함. 100개면 나머지 95개는 쉼
1로 다시 init 해주면 문제발생안함. mutex -> 한개씩 사용하니까 -> 그래도 여러 스레드 쓸 수 있다.!