Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 백준9012
- 딥러닝
- 2019카카오코테
- 백준온라인저지
- java
- 카카오코테
- 백준가운데를말해요
- 냅색알고리즘
- BOJ1655
- 백준10828
- 확인문제
- 합성곱연산
- 코테
- KT포트포워딩
- 코드트리
- 웹개발기초
- 이것이자바다9장
- 이것이자바다확인문제
- 백준괄호
- 백준
- 가운데를말해요
- 운영체제
- 이것이자바다
- 스파르타코딩클럽
- BOJ
- 백준평범한배낭
- 백준스택
- 코딩테스트실력진단
- 윤곽선검출
- 컴퓨터비전
Archives
- Today
- Total
코딩하는 락커
15. 동시성 제어의 고전적 문제들: Chapter 7. Synchronization Examples (Part 1) 본문
7.1 고전적인 동기화 문제들
- 많은 클래스의 병행 제어 문제에 대한 예로서 중요한 여러가지 다른 동기화 문제 제시
- 유한 버퍼 문제
- Readers-Writers 문제
- 식사하는 철학자 문제
유한 버퍼 문제
- 6.1절의 유한 버퍼 환경의 생산자-소비자 문제 참고 (https://coding-rocker.tistory.com/133)
11. 프로세스 동기화: Chapter 6. Synchronization Tools (Part 1)
6.1 배경Background 프로세스가 병행concurrent 또는 병렬parallel로 실행될 때 여러 프로세스가 공유하는 데이터의 무결성에 문제가 생길 수 있음 생산자-소비자 문제 생산자: 버퍼에 새 항목을 초기화
coding-rocker.tistory.com
- 동기화 문제 - 유한버퍼문제(생산자 소비자 문제)
- 생산자producer는 생산할 공간이 있을 경우에만 버퍼에 접근할 수 있어야 함
- 소비자consumer는 소비할 아이템이 있는 경우에만 버퍼에 접근할 수 있어야 함
- 문제 해결
- n개의 버퍼로 구성된 풀pool이 있다고 가정
- 각 버퍼는 한개의 아이템을 저장할 수 있다고 가정
- mutex 이진 세마포가 있다고 가정
- 버퍼 풀에 접근하기 위한 상호 배제 기능을 제공
- 1으로 초기화
- empty 세마포가 있다고 가정
- 비어있는 버퍼의 수를 기록
- n으로 초기화
- full 세마포가 있다고 가정
- 꽉 찬 버퍼의 수를 기록
- 0으로 초기화
int n;
semaphore mutex = 1;
semaphore empty = n;
semaphore full = 0;
// 생산자 코드
while(true){
/* 버퍼에 저장될 다음 아이템 생산 */
...
wait(empty); // 소비자가 버퍼를 다 비울 때 까지 기다림
wait(mutex); // 여러 생산자 중 한 개의 생산자만 버퍼에 접근할 수 있도록 동기화 해 줌
...
/* 다음 아이템을 버퍼에 추가 */
...
signal(mutex); // 다음 생산자가 버퍼에 접근할 수 있도록 함
signal(full); // 소비자에게 꽉 찬 버퍼가 생겼음을 알림
}
// 소비자 코드
while(true){
wait(empty); // 생산자가 버퍼를 다 채울 때 까지 기다림
wait(mutex); // 여러 소비자 중 한 개의 소비자 버퍼에 접근할 수 있도록 동기화 해 줌
...
/* 버퍼로부터 다음 아이템을 삭제 */
...
signal(mutex); // 다음 소비자 버퍼에 접근할 수 있도록 함
signal(full); // 생산자에게 비어있는 버퍼가 생겼음을 알림
...
/* 다음 아이템을 소비 */
}
- 실습 코드
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define true 1
#define BUFFER_SIZE 1
// 공유 버퍼
int buffer[BUFFER_SIZE];
pthread_mutex_t mutex;
sem_t empty, full;
int in = 0, out = 0;
void insert_item(int item){
sem_wait(&empty); // wait
pthread_mutex_lock(&mutex);
// ciritcal section
buffer[in] = item;
in = (in + 1) % BUFFER_SIZE;
printf("Producer: inserted $%d\n", item);
pthread_mutex_unlock(&mutex);
sem_post(&full); // signal
}
void remove_item(int *item){
sem_wait(&full); // wait
pthread_mutex_lock(&mutex);
*item = buffer[out];
out = (out + 1) % BUFFER_SIZE;
printf("Consumer: removed $%d\n", *item);
pthread_mutex_unlock(&mutex);
sem_post(&empty); // signal
}
void *producer(void *param){
int item;
while (true){
// 0.1초 ~ 0.5초 사이를 슬립하게 해줌
usleep((1+rand()%5)*100000);
// 1000 ~ 2000까지의 수를 랜덤하게 만들어줌
item = 1000 + rand()%1000;
// 랜덤값을 버퍼에 집어 넣음
insert_item(item); // critical section
}
}
void *consumer(void *param){
int item;
while (true){
// 0.1초 ~ 0.5초 사이를 슬립하게 해줌
usleep((1+rand()%5)*100000);
// item을 하나 꺼내옴
remove_item(&item); // critical section
}
}
int main(int argc, char const *argv[])
{
int i, numOfProducers = 1, numOfConsumers = 5;
pthread_t tid;
// 뮤텍스 초기화
pthread_mutex_init(&mutex, NULL);
// 버퍼 사이즈로 empty 초기화
sem_init(&empty, 0, BUFFER_SIZE);
// full 초기화
sem_init(&full, 0, 0);
for (int i=0; i<numOfProducers; i++){
pthread_create(&tid, NULL, producer, NULL);
}
for (int i=0; i<numOfConsumers; i++){
pthread_create(&tid, NULL, consumer, NULL);
}
sleep(5);
return 0;
}
Readers-Writers 문제
- 하나의 데이터베이스가 다수의 병행 프로세스간에 공유된다고 가정
- 동기화 문제(Readers-Writers 문제)
- reader: 데이터베이스의 내용을 읽기만 하는 프로세스
- writer: 데이터 베이스의 내용을 갱신(읽고 쓰기)하는 프로세스
- 하나의 Writer와 어떤 다른 스레드(reader 또는 writer)가 동시에 데이터베이스에 접근하면 혼란이 야기될 수 있음
- 첫 번째 Readers-Writers 문제
- writer가 공유 객체를 사용할 수 있는 허가를 아직 얻지 못했다면, 어느 reader도 기다리게 해서는 안됨
- writer가 기아starvation 상태에 빠질 수 있음
- 두 번째 Readers-Writers 문제
- writer가 준비 되면 가능한 빨리 쓰기를 수행해야함
- reader가 기아starvation 상태에 빠질 수 있음
- 첫 번째 Readers-Writers 문제 해결
- read_count가 있다고 가정
- 현재 몇 개의 프로세스들이 객체를 읽고 있는지 알려줌
- 0으로 초기화
- rw_mutex 이진 세마포가 있다고 가정
- writer들을 위한 상호 배제 세마포
- 첫 번째 reader와 임계구역을 빠져나오는 마지막 reader에 의해서도 사용됨
- reader와 writer가 모두 공유
- 1으로 초기화
- mutex 세마포가 있다고 가정
- read_count를 갱신할 때 상호 배제를 보장하기 위해 사용
- 1으로 초기화
- read_count가 있다고 가정
semaphore rw_mutex = 1;
semaphore mutex = 1;
int read_count = 0;
// writer 프로세스 코드
while(true){
wait(rw_mutex); // reader 혹은 writer가 signal(rw_mutex)를 수행할 때 까지 대기
...
/* 쓰기 작업 수행 */
...
signal(rw_mutex); // signal(rw_mutex)를 수행하여 대기중인 관련 큐에 있는 reader, writer 프로세스들을 깨움
}
while(true){
// n개의 reader가 기다리고 있다고 할 때
// wait(mutext)에 의해 n-1개의 reader는 mutex 관련 큐에 삽입됨
wait(mutex); // critical section인 read_count에 진입하기 위해 동기화
read_count++;
if (read_count == 1)
wait(rw_mutex); // 한 개의 reader(첫번째로 임계구역에 진입하는 reader 프로세스)가 rw_mutex관련 큐에 진입했다가 writer가 signal(rw_mutex)를 수행하면 깨어남
signal(mutex); // critical section인 read_count에 진입해도 됨을 알림
...
/* 읽기 작업 수행 */
...
wait(mutex); // c
read_count--; // critical section인 read_coun에 진입하기 위해 동기화
if (read_count == 0)
signal(rw_mutex); // 한 개의 reader(마지막으로 임계구역에 진입하는 reader 프로세스)가 rw_mutex관련 큐에 있는 writer 프로세스들을 깨움
signal(mutex); // critical section인 read_count에 진입해도 됨을 알림
}
- CashBox를 이용한 Reader-Writer 실습 코드
package com.os_study;
public class BoundedBuffer {
public static void main(String[] args) {
CashBox cashBox = new CashBox(1);
Thread[] producers = new Thread[5];
Thread[] consumers = new Thread[5];
for (int i = 0; i < producers.length; i++) {
producers[i] = new Thread(new ProdRunner(cashBox));
producers[i].start();
}
for (int i = 0; i < consumers.length; i++) {
consumers[i] = new Thread(new ConsRunner(cashBox));
consumers[i].start();
}
}
static class CashBox {
private int[] buffer;
private int count, in, out;
public CashBox(int buffersize){
buffer = new int[buffersize];
count = in = out = 0;
}
synchronized public void give(int money) throws InterruptedException {
while (count == buffer.length) {
try {
wait();
} catch (InterruptedException e) {
}
}
buffer[in] = money;
in = (in+1)% buffer.length;
count++;
System.out.printf("여기있다, 용돈: %d\n", money);
notify();
}
synchronized public int take() throws InterruptedException {
while(count == 0){
try {
wait();
}
catch (InterruptedException e){}
}
int money = buffer[out];
out = (out+1)%buffer.length;
count--;
System.out.printf("고마워요, 용돈: %d원\n", money);
notify();
return money;
}
}
private static class ProdRunner implements Runnable {
CashBox cashBox;
public ProdRunner(CashBox cashBox) {
this.cashBox = cashBox;
}
@Override
public void run() {
try {
while (true) {
Thread.sleep((long) (Math.random() * 500));
int money = ((int) (1 + Math.random() * 9)) * 10000;
cashBox.give(money);
}
} catch (InterruptedException e) {
}
}
}
private static class ConsRunner implements Runnable {
CashBox cashBox;
public ConsRunner(CashBox cashBox) {
this.cashBox = cashBox;
}
@Override
public void run() {
try {
while (true) {
Thread.sleep((long) (Math.random() * 500));
int money = cashBox.take();
cashBox.give(money);
}
} catch (InterruptedException e) {}
}
}
}
- SharedDB를 이용한 Reader-Writer 실습 코드
package com.os_study;
public class ReadersCounters {
static class SharedDB{
private int readerCount = 0;
private boolean isWriting = false;
public void read(){
// read from the database here.
}
public void write(){
// write into database here.
}
synchronized public void acquiredReadLock(){
while(isWriting == true){
try {
wait();
} catch (InterruptedException e) {}
}
readerCount++;
}
synchronized public void releasedReadLock(){
readerCount--;
if (readerCount == 0){
notify();
}
}
synchronized public void acquiredWriteLock(){
while(readerCount > 0 || isWriting == true){
try {
wait();
} catch (InterruptedException e) {}
}
isWriting = true;
}
synchronized public void releasedWriteLock(){
isWriting = false;
notifyAll();
}
}
public static void main(String[] args) {
SharedDB sharedDB = new SharedDB();
sharedDB.acquiredReadLock();
sharedDB.read();
sharedDB.releasedReadLock();
sharedDB.acquiredWriteLock();
sharedDB.write();
sharedDB.releasedWriteLock();
}
}
'📀 운영체제' 카테고리의 다른 글
17. 데드락의 이해: Chapter 8. Deadlocks (Part 1) (0) | 2022.06.20 |
---|---|
16. 철학자들은 왜 굶어 죽었을까?: Chapter 7. Synchronization Examples (Part 2 ~ Part 3) (0) | 2022.06.20 |
14. 모니터와 자바 동기화: Chapter 6. Synchronization Tools (Part 4) (0) | 2022.06.13 |
13. 뮤텍스와 세마포어: Chapter 6. Synchronization Tools (Part 3) (0) | 2022.06.13 |
12. 동기화 문제의 해결책: Chapter 6. Synchronization Tools (Part 2) (0) | 2022.06.07 |
Comments