일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 유스케이스
- 운영체제
- 배경 그림
- Unity #Indie Game
- OSI 7계층
- frequency-domain spectrum analysis
- MLFQ
- 메카님
- 컴퓨터 네트워크
- SDLC
- polymorphism
- protection
- 유니티
- link layer
- Security
- MAC
- STCF
- DSP
- 게임 개발
- DP
- information hiding
- OWASP
- 게임개발
- Waterfall
- stride
- Trap
- unity
- FIFO
- AINCAA
- SJF
- Today
- Total
다양한 기록
Semaphore (세마포) 본문
락을 위해서도 조건변수를 위해서도 사용 가능
sem_init(semaphore, p_shared, initial_value)
semaphre : 사용할 세마포
p_shared : 프로세스 간 쉐어, 안하면 0으로 설정하면 됨
initial_value : 이걸 어떻게 사용할 건지에 따라 바이너리 세마포, 카운팅 세마포. 사용법이 다름
int sem_wait(sem_t *s) // 세마포의 값을 1 내리고 음수면 웨이트
int sem_post(sem_t *s) // 세마포의 값을 1 올리고 대기 중인 스레드 하나 꺠우기
두 함수를 사용해서 세마포 사용
sem_t m;
sem_init(&m, 0, 1);
sem_wait(&m);
// critical section
sem_post(&m);
락으로 사용하는 경우, 바이너리 세마포
세마포의 값을 1로 준다
값이 1 : 들어와도 된다. 들어오는 스레드는 값을 1 내리고 0으로 만들 것
값이 0 : 누가 수행 중이고, 기다리는 스레드는 없다. 들어오는 스레드는 값을 음수로 만들고 슬립
값이 -1, -2, -3.... : 기다리는 스레드가 절댓값만큼 있다.
sem_t s;
void *s child(void *arg) {
printf("child\n");
sem_post(&s);
return NULL;
}
int main(int argc, char *argv[]) {
sem_init(&s, 0, 0);
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL);
sem_wait(&s);
printf("parent: end\n");
return 0;
}
조건변수로 사용하는 경우,
세마포의 값을 0으로 줘야 함
부모 스레드에서는 0인 세마포의 값을 -1로 만들고 슬립
-> 자식 스레드가 끝나기 전 세마포 값읗 1 증가시켜 0으로 만들고 종료
-> 이제 세마포 값이 음수가 아니니 부모 스레드 실행 가능
sem_t empty;
sem_t full;
sem_t mutex;
void *producer(void *arg) {
int i;
for( i = 0; i < loops; i++ ) {
sem_wait(&empty);
sem_wait(&mutex);
put(i);
sem_post(&mutex);
sem_post(&full);
}
}
void *consumer(void *arg) {
int i;
for( i = 0; i < loops; i++ ) {
sem_wait(&full);
sem_wait(&mutex);
put(i);
sem_post(&mutex);
sem_post(&empty);
}
}
mutex -> 바이너리 세마포
full, emtpy -> 카운팅 세마포
일반 조건변수와 다르게, 조건 변수가 락 바깥에 존재
full은 처음엔 0으로 초기화 (버퍼가 비어 있으니까)
empty는 최대 버퍼 크기로 초기화
Read / Writer Problem
판독자는 읽기만 하니까, 판독자 끼리는 상호배제(락)이 필요 없음
기록자 간에는 전통적인 방법으로 락하면 됨
typedef struct _rwlock_t {
sem_t lock; // 기록자들 락
sem_t writelock; // 메인 락
int readers;
} rwlock_t;
void rwlock_acquire_readlock(rwlock_t *rw) {
sem_wait(&rw->lock);
rw->readers++;
if( rw-> readers == 1 )
sem_wait(&rw->writelock);
sem_post(&rw->lock);
}
void rwlock_release_readlock(rwlock_t *rw) {
sem_wait(&rw->lock);
rw->readers--;
if( rw-> readers == 0 )
sem_post(&rw->writelock);
sem_post(&rw->lock);
}
void rwlock_acquire_writelock(rwlock_t *rw) {
sem_wait(&rw->writelock);
}
void rwlock_release_writelock(rwlock_t *rw) {
sem_post(&rw->writelock);
}
기록자: 라이트락을 걸고, 풀기만 하면 됨
판독자
기록자들은 락을 잡고 카운터를 증가 -> 1이면 혼자 있는 것
혼자 있으면 기록자가 쓰고 있는지 아닌지 모르기 때문에 라이트락도 잡고 들어가야 함
2 이상이다 -> 먼저 들어간 기록자가 있는 것 -> 라이트락 확인할 필요가 없어짐
언락 시에는 반대로 카운터를 감소시키는데, 0이면 마지막으로 나가는 판독자라 라이트락을 언락해줘야 함
The Dining Philosophers
5명의 철학자, 5개의 포크 / 먹거나 생각하거나 둘 중 하나의 행동
각 철학자는 자신의 왼쪽, 오른쪽 포크 두 개를 사용해야 식사가 가능
포크: 공유자원
void get_forks(int p) {
sem_wait(&forks[left(p)]);
sem_wait(&forks[right(p)]);
}
void put_forks(int p) {
sem_post(&forks[left(p)]);
sem_post(&forks[right(p)]);
}
전부 자신의 왼쪽 것부터 집게 되는 상황 -> 데드락 유발
해결책
1. 순서 바꾸기
2. 철학자 수 제한하기
3. 트랜잭션 도입 (모니터)
4. 포크 더 쓰기
5. 포크 하나로 먹을 수 있게 만들기
* 트라이락: 못잡으면 undo
-> 5명이 놓고 잡고만 반복하는 라이브락 상태가 될 수 있음
우선순위도 무엇에 우선순위를 높게 줄 것인가 등, 어렵긴 해도 해결책은 될 것
'운영체제' 카테고리의 다른 글
I/O Device, Device Driver (0) | 2024.05.06 |
---|---|
데드락 (0) | 2024.05.06 |
조건 변수, 생산자/소비자 문제 (0) | 2024.04.18 |
Lock-based Concurrent Data Structure (0) | 2024.04.18 |
Lock의 구현 (0) | 2024.04.11 |