Kernel Synchronization (Windows)
유니프로세서 시스템에서는 인터럽트 마스크를 사용해서 전역 자원에 대한 접근을 보호한다.
멀티프로세서 시스템에서는 스핀락을 사용한다. - 스핀락을 사용하는 스레드는 선점되지 않는다. (스핀락을 사용하는 스레드가 선점되면 데드락 발생)
사용자 레벨에서 동작하는 디스패처 객체를 제공한다. 이는 뮤텍스, 세마포어, 이벤트, 타이머로 작동된다.
타이머는 시간이 만료되면 하나 이상의 스레드에게 알린다.
이벤트는 조건변수와 유사하게 작동한다. - 어떤 조건을 만족하면 기다리던 스레드에게 notify()
디스패처 객체는 신호가 있는 상태(객체 사용 가능), 신호가 없는 상태(스레드가 차단됨)으로 나뉜다.
디스패처 객체마다 waiting queue가 있다. 오브젝트가 signaled-state로 바뀌면 큐에 대기하던 모든 스레드 또는 일부를 깨운다.
Linux Synchronization
커널 버전 2.6 이전에는 단기적인 CS를 구현하기 위해 인터럽트를 비활성화했고, 2.6버전 이상부터는 완전히 선점형이다.
리눅스는 세마포어, atomic integers(원자 정수), 스핀락, 뮤텍스 락을 제공한다.
리눅스의 스핀락과 뮤텍스락은 nonrecursive, 즉 이미 락을 획득한 상태에서 다시 락을 걸 수 없다.
단일 CPU 시스템에서는 스핀락을 커널 선점을 활성화/비활성화함으로 대체한다.
kernel에 있는 task가 lock을 가지고 있으면 그 task는 nonpreemptive함. (교착상태 방지)
현재 가지고 있는 lock의 수를 preempt_count란 변수에 저장하고 이 값이 0일 때 preemption 가능
POSIX Synchronization
POSIX API에서는 뮤텍스 락, 세마포어, 조건 변수를 제공한다. - Unix, Linux, macOS에서 사용됨.
POSIX mutex에는 다음과 같은 함수가 있다.
int pthread_mutex_init(pthread_mutex_t *restrict, const pthread_mutexattr_t * restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
POSIX semaphore에는 다음과 같은 함수가 있다.
// named
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
int sem_close(sem_t *sem);
int sem_unlink(const char *name);
// unnamed
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
POSIX condition variables에는 다음과 같은 함수가 있다.
pthread_cond_init(pthread_cond_t *cond, attr);
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
Transactional Memory
void update(){
atomic{
//원자적으로 실행돼야 할 구역
}
}
atomic{S}는 S를 트랜잭션으로 실행하라는 뜻이다.
트랜잭션은 모든 연산이 올바르게 처리되어 commit되거나, 또는 취소돼서 원점으로 롤백하는 두 가지 행동을 한다.
OpenMP
#pragma omp parallel
{
void update(int value){
#pragma omp critical
{
// 원자적으로 실행돼야 할 구역
}
}
}
OpenMP의 #pragma omp critical을 사용하여 원자적으로 실행되도록 할 수 있다.
Functional Programming Languages
함수형 프로그래밍 언어는 상태를 유지하지 않는다.
변수는 불변으로 취급되고, 한 번 값이 할당되면 상태를 변경할 수 없다.
따라서 멀티 스레드 환경에서 동시성 문제를 피할 수 있다.
'학교강의필기장 > 운영체제론' 카테고리의 다른 글
운영체제론[14]: 메모리 - 1 (0) | 2023.06.22 |
---|---|
운영체제론[13]: 데드락 (0) | 2023.06.22 |
운영체제론[11]: 스레드 동기화 (하드웨어 명령어) (0) | 2023.06.22 |
운영체제론[10]: 스레드 동기화 (이론편) (0) | 2023.06.22 |
운영체제론[9]: CPU 스케줄러 2 (0) | 2023.04.24 |