Post

[OS] Operating System(7-2): Synchronization(Windows, Linux, POSIX)

[OS] Operating System(7-2): Synchronization(Windows, Linux, POSIX)

๐Ÿ€ ์šด์˜์ฒด์ œ ์ „๊ณต ์ˆ˜์—… ์ •๋ฆฌ

Kernel Synchronizatoin - Windows


  • uniprocessor systems: Interrupt Mask๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ global resource์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ๋ณดํ˜ธ
    • Interrupt Mask: ํŠน์ • ์ธํ„ฐ๋ŸฝํŠธ์˜ ์ฒ˜๋ฆฌ๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ์ฐจ๋‹จ โ†’ ์ค‘์š”ํ•œ ์ฝ”๋“œ ์„น์…˜์ด ๋ฐฉํ•ด๋ฐ›์ง€ ์•Š๊ณ  ์‹คํ–‰๋จ
  • multiple processor system: spinlock ์‚ฌ์šฉํ•˜์—ฌ global resource์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ๋ณดํ˜ธ
    • spinlock: ๋ฝ์„ ํš๋“ํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์†ํ•ด์„œ ํ™•์ธํ•˜๋Š”(spinning) ๋ฐฉ์‹์˜ ๋ฝ
    • spinlock์„ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ๋Š” never be preempted
    • โ†’ ํšจ์œจ์„ฑ ๋•Œ๋ฌธ!: spinlock์„ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ๊ฐ€ ์„ ์ ๋˜๋ฉด deadlock์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค

Dispatcher Objects

  • Dispatcher Objects: ์œˆ๋„์šฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์‚ฌ์šฉ์ž ๋ ˆ๋ฒจ์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ฐ์ฒด(mutex, semaphore, events, timers)
    • mutex: ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ์œ„ํ•œ ๊ฐ์ฒด
    • semaphore: ์ œํ•œ๋œ ์ž์› ๊ด€๋ฆฌ
    • events: ์กฐ๊ฑด ๋งŒ์กฑ ์‹œ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์Šค๋ ˆ๋“œ์—๊ฒŒ notify()
    • timers: ์‹œ๊ฐ„์ด ๋งŒ๋ฃŒ๋˜๋ฉด ํ•˜๋‚˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ์— notify()

dispatcher object๋Š” ๋‘ ๊ฐœ์˜ ์ƒํƒœ๊ฐ€ ์กด์žฌ:

  1. Signaled State: ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ƒํƒœ
  2. Non-signal State: ์Šค๋ ˆ๋“œ๊ฐ€ ๋ธ”๋ก๋˜๋Š” ์ƒํƒœ

๊ฐ dispatcher object์—๋Š” waiting queue๊ฐ€ ์กด์žฌ!
Object๊ฐ€ signaled-state๋กœ ๋ฐ”๋€Œ๋ฉด queue์— ๋Œ€๊ธฐํ•˜๋˜ ๋ชจ๋“  ์Šค๋ ˆ๋“œ ๋˜๋Š” ์ผ๋ถ€๋ฅผ ๊นจ์šด๋‹ค

alt text

Mutex Dispatcher Object

์ž‘๋™ ๋ฐฉ์‹:

  1. ์Šค๋ ˆ๋“œ๊ฐ€ mutex_lock์„ ํš๋“ํ•˜๋ฉด mutex๋Š” Non-signal state
  2. ์†Œ์œ ์ž ์Šค๋ ˆ๋“œ๊ฐ€ mutex_lock๋ฅผ ํ•ด์ œํ•˜๋ฉด Signal state
  3. ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ mutex_lockํš๋“ ๊ฐ€๋Šฅ

Linux Synchronization


2.6๋ฒ„์ „ ์ด์ „์˜ ์ปค๋„์—์„œ๋Š” disables interrupt๋ฅผ ์‚ฌ์šฉํ•ด์„œ CS๋ฅผ ๊ตฌํ˜„

โœ…2.6์ดํ›„ ๋ฒ„์ „:

  • fully preemptive๋ฐฉ์‹ ์ฑ„ํƒ
  • ์ปค๋„ ์ฝ”๋“œ ์‹คํ–‰ ์ค‘์—๋„ ๋” ๋†’์€ ์šฐ์„ ์ˆœ์œ„์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค๋ฅผ ์„ ์ ํ•  ์ˆ˜ ์žˆ์Œ

Linux provides


  1. Semaphore
    • ์ž์›์˜ ๊ฐœ์ˆ˜๋ฅผ ์นด์šดํŒ…ํ•˜์—ฌ ์ œํ•œ๋œ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ž์›์— ์ ‘๊ทผ ๊ฐ€๋Šฅ
  2. Atomic Integers
    • ์›์ž์  ์—ฐ์‚ฐ์„ ์ง€์›ํ•˜๋Š” ํŠน์ˆ˜ํ•œ ์ •์ˆ˜ ํƒ€์ž…(atomic_t)
  3. Spinlock
    • ๋ฝ์„ ํš๋“ํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์†ํ•ด์„œ ํ™•์ธํ•˜๋Š”(spinning) ๋ฐฉ์‹์˜ ๋ฝ
  4. Mutex Locks
    • ์ƒํ˜ธ ๋ฐฐ์ œ(Mutual Exclusion)๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฝ
  • ๋ฆฌ๋ˆ…์Šค์˜ ์Šคํ•€๋ฝ๊ณผ ๋ฎคํ…์Šค ๋ฝ์€ nonrecursive ํŠน์„ฑ
  • โ†’ ๋ฝ์„ ์ด๋ฏธ ํš๋“ํ•œ ์ƒํƒœ์—์„œ ๋‹ค์‹œ ํš๋“ํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

  • Single-CPU System: disabling kernel preemption ์‚ฌ์šฉ
    • spinlock์€ ๋‹จ์ผ CPU์—์„œ ๋น„ํšจ์œจ์ ์ด๊ธฐ ๋•Œ๋ฌธ
  • SMP(Symmetric Multi-Processing): spinlock ์‚ฌ์šฉ
    • ์—ฌ๋Ÿฌ CPU๊ฐ€ ๋™์‹œ์— ์ž‘์—… ์ฒ˜๋ฆฌ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— spinlock ํšจ์œจ ํ–ฅ์ƒ
  • ์ปค๋„์— ์žˆ๋Š” task๊ฐ€ lock ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์ด task๋Š” nonpreemptive
  • preemptiveํ•˜๋ฉด deadlock ๋ฐœ์ƒ ๊ฐ€๋Šฅ
  • ํ˜„์žฌ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” lock์˜ ์ˆ˜๋ฅผ preempt_count๋ผ๋Š” ๋ณ€์ˆ˜์— ์ €์žฅ
  • preempt_count=0 ์ด๋ฉด preemption ๊ฐ€๋Šฅ!!

Atomic Variables


  • atimic_t type:
    1
    2
    
    atomic_t counter;
    int value;
    

์ฃผ์š” atomic ์—ฐ์‚ฐ: alt text

C11 atomic library: alt text

  • atomic_init(_Atomic(T) *object, T value): ๋น„์›์ž์ ์œผ๋กœ ์ดˆ๊ธฐํ™”
  • T atomic_load(_Atomic(T) *object): ์›์ž์ ์œผ๋กœ ๊ฐ’ ์ฝ๊ธฐ
  • void atomic_store(_Atomic(T) *object, T desired): ์›์ž์ ์œผ๋กœ ๊ฐ’ ์ €์žฅ
  • T atomic_exchange(_Atomic(T) *object, T desired): ์›์ž์ ์œผ๋กœ ๊ฐ’ ๊ตํ™˜
  • _Bool atomic_compare_exchange_strong/_weak(_Atomic(T) *object, T *expected, T desired): ๋น„๊ต ํ›„ ๊ตํ™˜
  • T atomic_fetch_add/_and/_or/_sub/_xor(_Atomic(T) *object, T operand): ์—ฐ์‚ฐ ํ›„ ์ด์ „ ๊ฐ’ ๋ฐ˜ํ™˜

POSIX Synchronization


POSIX API๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณต

POSIX Provides


  • Mutex Locks: ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ์œ„ํ•œ ๋ฝ
  • Spin Locks: ์งง์€ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์œ„ํ•œ ๋ฝ
  • Semaphores: ์ž์› ์นด์šดํŒ…์„ ์œ„ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • Condition Variables: ํŠน์ • s์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ์Šค๋ ˆ๋“œ๋ฅผ ๋Œ€๊ธฐ์‹œํ‚ค๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜

์ฃผ์š” ํ•จ์ˆ˜:

1
2
3
4
5
6
7
8
9
10
11
12
// ๋ฎคํ…์Šค ์ƒ์„ฑ ๋ฐ ํŒŒ๊ดด
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(pthread_mutex_t *restrict mutex, 
                      const pthread_mutexattr_t *restrict attr);

// ์ •์  ์ดˆ๊ธฐํ™”
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// ๋ฎคํ…์Šค ์ž ๊ธˆ ๋ฐ ํ•ด์ œ
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

๋ฎคํ…์Šค ์‚ฌ์šฉ ์˜ˆ์‹œ

  • ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™”:
1
2
3
4
5
6
#include <pthread.h>

pthread_mutex_t mutex;

/* ๋ฎคํ…์Šค ๋ฝ ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™” */
pthread_mutex_init(&mutex, NULL);
  • ํš๋“ ๋ฐ ํ•ด์ œ:
1
2
3
4
5
6
7
/* ๋ฎคํ…์Šค ๋ฝ ํš๋“ */
pthread_mutex_lock(&mutex);

/* ์ž„๊ณ„ ์˜์—ญ */

/* ๋ฎคํ…์Šค ๋ฝ ํ•ด์ œ */
pthread_mutex_unlock(&mutex);

POSIX Spinlock

  • spinlock ์ฃผ์š” ํ•จ์ˆ˜:
1
2
3
4
5
6
7
8
#include <pthread.h>

int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);

int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);
  • int pshared์—์„œ pshared ์˜ต์…˜:
    • PTHREAD_PROCESS_PRIVATE: ํ”„๋กœ์„ธ์Šค ๋‚ด ์Šค๋ ˆ๋“œ๊ฐ„ ๊ณต์œ  (๊ธฐ๋ณธ๊ฐ’)
    • PTHREAD_PROCESS_SHARED: ํ”„๋กœ์„ธ์Šค ์™ธ ์Šค๋ ˆ๋“œ๊ฐ„ ๊ณต์œ  (๋ฝ์ด ๊ณต์œ  ๋ฉ”๋ชจ๋ฆฌ ์ƒ์— ์žˆ์–ด์•ผ ํ•จ)

POSIX Semaphore

POSIX๋Š” ๋‘ ๊ฐ€์ง€ ๋ฒ„์ „์˜ ์„ธ๋งˆํฌ์–ด ์ œ๊ณต

  1. Named Semaphores
    • ์„œ๋กœ ๊ด€๋ จ ์—†๋Š” ํ”„๋กœ์„ธ์Šค ๊ฐ„์—๋„ ๊ณต์œ  ๊ฐ€๋Šฅ
  2. Unnamed Semaphores
    • ๊ด€๋ จ๋œ ํ”„๋กœ์„ธ์Šค(์˜ˆ: ๋ถ€๋ชจ-์ž์‹) ๊ฐ„์—๋งŒ ๊ณต์œ  ๊ฐ€๋Šฅ
๊ณตํ†ต ํ•จ์ˆ˜
  • sem_wait(sem_t *sem): ์„ธ๋งˆํฌ์–ด ๊ฐ’์„ ๊ฐ์†Œ์‹œํ‚ค๊ณ , ๊ฐ’์ด 0์ด๋ฉด ๋ธ”๋ก๋จ (P ์—ฐ์‚ฐ)
  • sem_post(sem_t *sem): ์„ธ๋งˆํฌ์–ด ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ , ๋Œ€๊ธฐ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค ๊นจ์›€ (V ์—ฐ์‚ฐ)
  • sem_trywait(sem_t *sem): ๋น„๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ wait ์‹œ๋„
  • sem_timedwait(sem_t *sem, const struct timespec *abs_timeout): ์ œํ•œ ์‹œ๊ฐ„ ๋‚ด์— wait ์‹œ๋„
  • sem_getvalue(sem_t *sem, int *sval): ํ˜„์žฌ ์„ธ๋งˆํฌ์–ด ๊ฐ’ ์กฐํšŒ
Named semaphore ํ•จ์ˆ˜
  • sem_t *sem_open(const char *name, int oflag): ๊ธฐ์กด ์„ธ๋งˆํฌ์–ด ์—ด๊ธฐ
  • 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 semaphore ํ•จ์ˆ˜
  • int sem_init(sem_t *sem, int pshared, unsigned int value): ์„ธ๋งˆํฌ์–ด ์ดˆ๊ธฐํ™”
  • int sem_destroy(sem_t *sem): ์„ธ๋งˆํฌ์–ด ํŒŒ๊ดด
Named Semaphores
  • Named Semaphores: ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฒฝ๋กœ๋ช…์œผ๋กœ ์‹๋ณ„๋˜๋ฉฐ, ๊ด€๋ จ ์—†๋Š” ํ”„๋กœ์„ธ์Šค ๊ฐ„์—๋„ ๊ณต์œ  ๊ฐ€๋Šฅ

  • ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™”:

1
2
3
4
5
#include <semaphore.h>
sem_t *sem;

/* ์„ธ๋งˆํฌ์–ด ์ƒ์„ฑ ๋ฐ 1๋กœ ์ดˆ๊ธฐํ™” */
sem = sem_open("SEM", O_CREAT, 0666, 1);
  • SEM: ์„ธ๋งˆํฌ์–ด ์ด๋ฆ„
  • O_CREAT: ์„ธ๋งˆํฌ์–ด๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
  • 0666: ์ ‘๊ทผ ๊ถŒํ•œ (rw-rw-rw-)
    • rw ๊ถŒํ•œ์ด ์žˆ์–ด์•ผ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • 1: ์ดˆ๊ธฐ ์„ธ๋งˆํฌ์–ด ๊ฐ’

  • ํš๋“ ๋ฐ ํ•ด์ œ:
1
2
3
4
5
6
7
/* ์„ธ๋งˆํฌ์–ด ํš๋“ */
sem_wait(sem);

/* ์ž„๊ณ„ ์˜์—ญ */

/* ์„ธ๋งˆํฌ์–ด ํ•ด์ œ */
sem_post(sem);
Unnamed Semaphore
  • Unnamed Semaphore: ์ด๋ฆ„์ด ์—†๊ณ  ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋กœ ์ฐธ์กฐ, ์ฃผ๋กœ ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด์˜ ์Šค๋ ˆ๋“œ ๊ฐ„ ๋˜๋Š” ๊ด€๋ จ ํ”„๋กœ์„ธ์Šค ๊ฐ„(์˜ˆ: ๋ถ€๋ชจ-์ž์‹)์— ์‚ฌ์šฉ

  • ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐํ™”:

1
2
3
4
5
#include <semaphore.h>
sem_t sem;

/* ์„ธ๋งˆํฌ์–ด ์ƒ์„ฑ ๋ฐ 1๋กœ ์ดˆ๊ธฐํ™” */
sem_init(&sem, 0, 1);
  • &sem: ์„ธ๋งˆํฌ์–ด ํฌ์ธํ„ฐ
  • 0: pshared ๊ฐ’(๊ณต์œ  ๋ฒ”์œ„)
    • 0: ๊ฐ™์€ ํ”„๋กœ์„ธ์Šค ๋‚ด ์Šค๋ ˆ๋“œ ๊ฐ„ ๊ณต์œ 
    • Non-zero: ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๊ณต์œ (์„ธ๋งˆํฌ์–ด๊ฐ€ shared memory์— ์žˆ์–ด์•ผ ํ•จ)
  • 1: ์ดˆ๊ธฐ ์„ธ๋งˆํฌ์–ด ๊ฐ’

  • ํš๋“ ๋ฐ ํ•ด์ œ:
1
2
3
4
5
6
7
/* ์„ธ๋งˆํฌ์–ด ํš๋“ */
sem_wait(&sem);

/* ์ž„๊ณ„ ์˜์—ญ */

/* ์„ธ๋งˆํฌ์–ด ํ•ด์ œ */
sem_post(&sem);

POSIX Condition Variables

  • ์กฐ๊ฑด ๋ณ€์ˆ˜: ๋Œ€๊ธฐ์—ด์˜ ์ด๋ฆ„, ์Šค๋ ˆ๋“œ๋“ค์€ ํŠน์ • ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ์ด ๋Œ€๊ธฐ์—ด์—์„œ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜๋ฉด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด์–ด ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šด

  • POSIX๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ C/C++์—์„œ ์‚ฌ์šฉ๋จ, C/C++ ์–ธ์–ด๋Š” Monitor ์ œ๊ณต X
  • ๊ทธ๋ž˜์„œ POSIX ์กฐ๊ฑด๋ณ€์ˆ˜๋Š” mutual exclusion์„ ์œ„ํ•ด POSIX mutex lock๊ณผ ๊ฐ™์ด ์‚ฌ์šฉ๋œ๋‹ค

  • ์ดˆ๊ธฐํ™” ๋ฐ ํŒŒ๊ดด: ```c pthread_mutex_t mutex; pthread_cond_t cond_var;

// ๋™์  ์ดˆ๊ธฐํ™” pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond_var, NULL);

// ์ •์  ์ดˆ๊ธฐํ™” pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
**์ฃผ์š” ํ•จ์ˆ˜**:
* `pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)`: ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
* `pthread_cond_timedwait(...)`: ์ œํ•œ ์‹œ๊ฐ„ ๋‚ด์—์„œ ์กฐ๊ฑด ๋Œ€๊ธฐ
* `pthread_cond_signal(pthread_cond_t *cond)`: ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ ํ•˜๋‚˜๋ฅผ ๊นจ์›€
* `pthread_cond_broadcast(pthread_cond_t *cond)`: ๋Œ€๊ธฐ ์ค‘์ธ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์›€

**์กฐ๊ฑด ๋ณ€์ˆ˜ ์‚ฌ์šฉ ํŒจํ„ด**:
* ์กฐ๊ฑด์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์Šค๋ ˆ๋“œ (a == b๊ฐ€ ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆผ):

```c
pthread_mutex_lock(&mutex);
while (a != b) {
    pthread_cond_wait(&cond_var, &mutex);
}
pthread_mutex_unlock(&mutex);
  1. release mutex lock: pthread_cond_wait()๋Š” ๋ฎคํ…์Šค ๋ฝ์„ ํ’€์–ด์ฃผ๊ณ  ๋Œ€๊ธฐ ์ƒํƒœ ๋Œ์ž…
  2. wait on the condition variable: ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ผ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
  3. ๊นจ์–ด๋‚˜๋ฉด โ†’ acquire mutex lock and return

โœ…while ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ :
pthread_cond_wait()๋Š” ๋ฎคํ…์Šค ๋ฝ์„ ํ’€๊ธฐ ๋•Œ๋ฌธ์— a๋‚˜ b์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ. ๋”ฐ๋ผ์„œ while ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด์„ ๋‹ค์‹œ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”

  • ์กฐ๊ฑด์„ ์‹ ํ˜ธํ•˜๋Š” ์Šค๋ ˆ๋“œ:
    1
    2
    3
    4
    
    pthread_mutex_lock(&mutex);
    a = b;  // ์กฐ๊ฑด์„ ์ถฉ์กฑ์‹œํ‚ด
    pthread_cond_signal(&cond_var);
    pthread_mutex_unlock(&mutex);
    
  • pthread_cond_signal(&cond_var)
    • ์กฐ๊ฑด๋ณ€์ˆ˜์—์„œ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ๊นจ์–ด๋‚˜์˜ด
    • ์ด๋•Œ ๊นจ์–ด๋‚œ ์Šค๋ ˆ๋“œ๋Š” mutex lock์„ ํš๋“ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ด ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ ์•„์ง ์ง„ํ–‰์ด ์ •์ง€๋œ ์ƒํƒœ
  • pthread_mutex_unlock(&mutex)
    • a=b๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๊ฑธ์—ˆ๋˜ lock์„ signal์„ ํ˜ธ์ถœํ•œ ํ›„ unlock์„ ํ•˜๊ฒŒ๋˜๋ฉด, ๊นจ์–ด๋‚ฌ์ง€๋งŒ ์•„์ง ๋Œ€๊ธฐ์ƒํƒœ์— ์žˆ๋˜ ์Šค๋ ˆ๋“œ๊ฐ€ lock์„ ํš๋“ํ•œ ํ›„ ๋‹ค์Œ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค
  • pthread_cond_signal vs pthread_cond_broadcast pthread_cond_signal: ํ•˜๋‚˜์˜ ์ž‘์—…๋งŒ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ(์˜ˆ: ์ƒ์‚ฐ์ž-์†Œ๋น„์ž์—์„œ ํ•˜๋‚˜์˜ ์•„์ดํ…œ๋งŒ ์ค€๋น„๋œ ๊ฒฝ์šฐ)
  • ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ ํ•˜๋‚˜๋งŒ ๊นจ์›€
  • ์–ด๋–ค ์Šค๋ ˆ๋“œ๊ฐ€ ๊นจ์–ด๋‚ ์ง€๋Š” ์‹œ์Šคํ…œ์ด ๊ฒฐ์ •

pthread_cond_broadcast: ๋ชจ๋“  ๋Œ€๊ธฐ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์กฐ๊ฑด์„ ๋‹ค์‹œ ํ™•์ธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹ ํ˜ธ)

  • ๋Œ€๊ธฐ ์ค‘์ธ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์›€
  • ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๋ฎคํ…์Šค ๋ฝ์„ ํš๋“ํ•˜๋ ค๊ณ  ๊ฒฝ์Ÿ
  • ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ๋ฝ์„ ํš๋“ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋‹ค์‹œ ๋Œ€๊ธฐ์ƒํƒœ

Alternative Approaches


์ „ํ†ต์ ์ธ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜(๋ฎคํ…์Šค, ์„ธ๋งˆํฌ์–ด, ์กฐ๊ฑด ๋ณ€์ˆ˜) ์™ธ์— ๋ณ‘๋ ฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” Alternative Approaches ์กด์žฌ

  1. Transactional Memory
  2. OpenMP
  3. Functional Programming Languages

Transactional Memory


  • Transactional Memory: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํŠธ๋žœ์žญ์…˜ ๊ฐœ๋…์„ ๋ฉ”๋ชจ๋ฆฌ ์—ฐ์‚ฐ์— ์ ์šฉํ•œ ๊ฒƒ, ์—ฌ๋Ÿฌ ๋ฉ”๋ชจ๋ฆฌ ์ฝ๊ธฐ-์“ฐ๊ธฐ ์—ฐ์‚ฐ์„ ํ•˜๋‚˜์˜ ์›์ž์  ๋‹จ์œ„๋กœ ๋ฌถ์–ด์„œ ์ฒ˜๋ฆฌ

์ „ํ†ต์ ์ธ ๋ฐฉ์‹(๋ฎคํ…์Šค):

1
2
3
4
5
void update() {
    acquire();  // ๋ฎคํ…์Šค ๋ฝ ํš๋“
    /* modify shared data */
    release();  // ๋ฎคํ…์Šค ๋ฝ ํ•ด์ œ
}

ํŠธ๋žœ์žญ์…˜ ๋ฉ”๋ชจ๋ฆฌ:

1
2
3
4
5
void update() {
    atomic {
        /* modify shared data */
    }
}
  • ํŠธ๋žœ์žญ์…˜์€ atomic{S} ๊ตฌ๋ฌธ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” S ๋‚ด์˜ ๋ชจ๋“  ์—ฐ์‚ฐ์ด ์›์ž์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅ
    • ๋ชจ๋“  ์—ฐ์‚ฐ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋˜์–ด commit(ํ™•์ •)๋˜๊ฑฐ๋‚˜
    • ์ทจ์†Œ๋˜์„œ ์›์ ์œผ๋กœ ๋กค๋ฐฑํ•˜๋Š” ๋‘ ๊ฐ€์ง€๋งŒ ๊ฐ€๋Šฅ

OpenMP


  • OpenMP: ์ปดํŒŒ์ผ๋Ÿฌ ์ง€์‹œ๋ฌธ๊ณผ API๋ฅผ ํ†ตํ•ด ๋ณ‘๋ ฌ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ง€์›, ๊ธฐ์กด์˜ ์ˆœ์ฐจ ์ฝ”๋“œ๋ฅผ ๊ฐ„๋‹จํ•œ ์ง€์‹œ๋ฌธ ์ถ”๊ฐ€๋งŒ์œผ๋กœ ๋ณ‘๋ ฌํ™”ํ•  ์ˆ˜ ์žˆ์–ด ๋งค์šฐ ์‹ค์šฉ์ 

์ฃผ์š” ์ง€์‹œ๋ฌธ:

1
2
3
4
5
6
7
8
9
#pragma omp parallel  // ์ฝ”์–ด์˜ ์ˆ˜๋งŒํผ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ํ›„, ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋ผ
{
    void update(int value) {
        #pragma omp critical  // Atomically ์‹คํ–‰ํ•˜๋ผ
        {
            count += value;
        }
    }
}
  • #pragma omp parallel: ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”์–ด ์ˆ˜๋งŒํผ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰
  • #pragma omp critical: ํฌํ•จ๋œ ์ฝ”๋“œ ๋ธ”๋ก์„ ์ž„๊ณ„ ์˜์—ญ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ์›์ž์ ์œผ๋กœ ์‹คํ–‰
This post is licensed under CC BY 4.0 by the author.