25 ๋ณํ์ฑ์ ๊ดํ ๋ํ
์ฌ๋ฌ์ฌ๋์ด ๋์์ ๋ณต์ญ์๋ฅผ ์ง์ ์ ์๋๋ก ํ์๋๋ ๋นจ๋์ด์, ๋ฐ๋ฉด์ ์ ๋ฐฉ๋ฒ์ ํ๋ฒ์ ํ๋ช ์ฉ ์ง๊ธฐ ๋๋ฌธ์ ์ ํํ๊ฒ ์ง๋ง ๊ฝค ๋๋ฆฌ๊ฒ ๊ตฐ์.
๋ฉํฐ ์ฐ๋ ๋ ํ๋ก๊ทธ๋จ์ด๋ผ๊ณ ๋ถ๋ฆฌ๋ ํ๋ก๊ทธ๋จ๋ค์ด ์๋ค, ๊ฐ ์ฐ๋ ๋๋ ๋ ๋ฆฝ๋ ๊ฐ์ฒด๋ก์ ํ๋ก๊ทธ๋จ ๋ด์์ ํ๋ก๊ทธ๋จ์ ๋์ ํ์ฌ ์ผ์ผ ํ์ง, ์ด ์ฐ๋ ๋๋ค์ ๋ฉ๋ชจ๋ฆฌ์ ์ ๊ทผํ๋๋ฐ, ์ฐ๋ ๋ ์ ์ฅ์์ ๋ณด๋ฉด ๋ฉ๋ชจ๋ฆฌ๋ ์๊น ์ด์ผ๊ธฐํ๋ ๋ณต์ญ์์ ๊ฐ์ ๊ฑฐ์ผ
๋์์ฑ์ ์ด์์ฒด์ ์์ ๋ค๋ค์ผ ํ ๋ช ๊ฐ์ง ์ด์ ๊ฐ ์์ง. ์ด์์ฒด์ ๋ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์์ ๊ฐ์ ๊ธฐ๋ณธ ๋์ ์ผ๋ก ๋ฉํฐ์ฐ๋ ๋ ํ๋ก๊ทธ๋จ์ ์ง์ํด์ผ ํ๋ค๋ค. ๋์งธ๋ก ์ด์์ฒด์ ๋ ๊ทธ ์์ฒด๋ก ์ต์ด์ ๋์ ํ๋ก๊ทธ๋จ์ด๊ธฐ ๋๋ฌธ์ด์ผ
26 ๋ณํ์ฑ: ๊ฐ์
- ํ๋ก๊ทธ๋จ์์ ํ ์๊ฐ์ ํ๋์ ๋ช ๋ น์ด๋ง์ ์คํํ๋ (๋จ์ผ PC๊ฐ) ๊ณ ์ ์ ์ธ ๊ด์ ์์ ๋ฒ์ด๋ ๋ฉํฐ ์ฐ๋ ๋ ํ๋ก๊ทธ๋จ์ ํ๋ ์ด์์ ์คํ ์ง์ ์ ๊ฐ์ง๊ณ ์๋ค(๋ ๋ฆฝ์ ์ผ๋ก ๋ถ๋ฌ ๋ค์ฌ์ง๊ณ ์คํ๋ ์ ์๋ ์ฌ๋ฌ๊ฐ์ PC๊ฐ).
- ๋ฉํฐ ์ฐ๋ ๋๋ฅผ ์ดํดํ๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๊ฐ ์ฐ๋ ๋๊ฐ ํ๋ก์ธ์ค์ ๋งค์ฐ ์ ์ฌํ์ง๋ง, ์ฐจ์ด๊ฐ ์๋ค๋ฉด ์ฐ๋ ๋๋ค์ ์ฃผ์๊ณต๊ฐ์ ๊ณต์ ํ๊ธฐ ๋๋ฌธ์ ๋์ผํ ๊ฐ์ ์ ๊ทผํ ์์๋ค๋ ๊ฒ์ด๋ค.
- ํ๋์ ์ค๋ ๋์ ์ํ๋ ํ๋ก์ธ์ค์ ์ํ์ ๋งค์ฐ ์ ์ฌํ๋ค. ์ค๋ ๋๋ ์ด๋์ ๋ช ๋ น์ด๋ฅผ ๋ถ๋ฌ๋ค์ผ์ง ์ถ์ ํ๋ ํ๋ก๊ทธ๋จ ์นด์ดํฐ์ ์ฐ์ฐ์ ์ํ ๋ ์ง์คํฐ๋ค์ ๊ฐ์ง๊ณ ์๋ค.
- ๋ง์ฝ ๋๊ฐ์ ์ค๋ ๋๊ฐ ํ๋์ ํ๋ก์ธ์์์ ์คํ์ค์ด๋ผ๋ฉด ์คํํ๊ณ ์ ํ๋ ์ค๋ ๋๋ ๋ฐ๋์ context switch์ ํตํด์ ์คํ์ค์ด ์ค๋ ๋์ ๊ต์ฒด๋์ด์ผ ํ๋ค.
- ์ค๋ ๋์ ๋ฌธ๋งฅ๊ตํ์ t1์ด ์ฌ์ฉํ๋ ๋ ์ง์คํฐ๋ค์ ์ ์ฅํ๊ณ t2๊ฐ ์ฌ์ฉํ๋ ๋ ์ง์คํฐ์ ๋ด์ฉ์ผ๋ก ๋ณต์ํ๋ค๋ ์ ์์ ํ๋ก์ธ์ค์ ๋ฌธ๋งฅ ๊ตํ๊ณผ ์ ์ฌํ๋ค.
- ํ๋ก์ธ์ค๊ฐ ๋ฌธ๋งฅ ๊ตํ์ ํผ ๋์ ํ๋ก์ธ์ค์ ์ํ๋ฅผ ํ๋ก์ธ์ค ์ ์ด ๋ธ๋ญ์ ์ ์ฅํ๋ฏ์ด ์ค๋ ๋๋ ์ค๋ ๋ ์ ์ด ๋ธ๋ญ์ด ํ์ํ๋ค.
- ๊ฐ์ฅ ํฐ ์ฐจ์ด์ค ํ๋๋ ํ๋ก์ธ์ค์ ๊ฒฝ์ฐ์ค ๋ฌ๋ฆฌ ์ค๋ ๋๊ฐ์ ๋ฌธ๋งฅ ๊ตํ์์๋ ์ฃผ์๊ณต๊ฐ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค๋ ๊ฒ์ด๋ค.
- ์ค๋ ๋์ ํ๋ก์ธ์ค์ ๋ ๋ค๋ ์ฐจ์ด๋ ์คํ์ ์๋ค. ๊ณ ์ ์ ํ๋ก์ธ์ค ์ฃผ์๊ณต๊ฐ๊ณผ ๊ฐ์ ๊ฐ๋จํ ๋ชจ๋ธ์์๋ ์คํ์ด ํ๋๋ง ์กด์ฌํ๋ค.(์ฃผ๋ก ์ฃผ์ ๊ณต๊ฐ์ ํ๋ถ์)
- ๋ฐ๋ฉด์ ๋ฉํฐ์ค๋ ๋ ํ๋ก์ธ์ค์ ๊ฒฝ์ฐ์๋ ๊ฐ ์ค๋ ๋๊ฐ ๋
๋ฆฝ์ ์ผ๋ก ์คํ๋๋ฉฐ ์ฃผ์๊ณต๊ฐ์๋ ํ๋์ ์คํ์ด ์๋๋ผ ์ค๋ ๋๋ง๋ค ์คํ์ด ํ ๋น๋์ด ์๋ค.
26.1 ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋๊ฐ?
- ์ฐ๋ฆฌ๋ ๋ฉํฐ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ฉด์ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ๋ฐฐ์ธ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๊ทธ ์ ์ ์ ์ฌ์ฉํ๋์ง์ ํจ์ฉ์ ๋ํด์ ์์๋ณผ๊ฒ์ด๋ค.
- ์ฃผ์ํ๊ฒ๋ ๋๊ฐ์ง ์ด์ ๊ฐ ์๋ค.
- ๋ณ๋ ฌ์ฒ๋ฆฌ (parallelism) :
- ์๋ฅผ ๋ค์ด ๋๊ฐ์ ํฐ ๋ฐฐ์ด์ ๋ํ๊ฑฐ๋, ๋ฐฐ์ด์ ๊ฐ ์์ ๊ฐ์ ์ฆ๊ฐ์ํค๋ ๊ฒ๊ณผ ๊ฐ์ด ๋งค์ฐ ํฐ ๋ฐฐ์ด์ ๋์์ผ๋ก ์ฐ์ฐ์ ์ํํ๋ ํ๋ก๊ทธ๋จ์ ์์ฑํ๊ณ ์๋ฐ๊ณ ๊ฐ์ ํด๋ณด์.
- ๋จ์ผํ๋ก์ธ์ค๋ ๊ฐ๋จํ๋ค - ๊ฐ ์์ ์ ํ๋์ฉ ์ํ ํ ์๋ฃ
- ๊ทธ๋ฌ๋ ๋ฉํฐํ๋ก์ธ์ค์์คํ ์์๋ ๊ฐ ํ๋ก์ธ์๊ฐ ์์ ์ ์ผ๋ถ๋ถ์ ์ํํ๊ฒ ํจ์ผ๋ก์จ ์คํ์๋๋ฅผ ๋์ผ์ ์๋ค.
- ํ์ค ๋จ์ผ ์ค๋ ๋ ํ๋ก๊ทธ๋จ์ ๋ฉํฐํ๋ก์ธ์์์์ ๊ฐ์ ์์ ์ ํ๋ ํ๋ก๊ทธ๋จ์ผ๋ก ๋ณํํ๋ ์์ ์ ๋ณ๋ คํ๋ผ๊ณ ํ๋ค.
- ๋๋ฒ์งธ๋ ์ฝ๊ฐ ๋ฏธ๋ฌํ๋ฐ, ๋๋ฆฐ I/O๋ก ์ธํด ํ๋ก๊ทธ๋จ ์คํ์ด ๋ฉ์ถ์ง ์๋๋ก ํ๊ธฐ ์ํด์ ์ค๋ ๋๋ฅผ ์ด์ฉํ๋ค.
- ํ๋ก๊ทธ๋จ์ค ํ๋์ ์ค๋ ๋๊ฐ ๋๊ธฐํ๋๋์ ์ค์ผ์ค๋ฌ๋ ๋ค๋ฅธ ์ค๋ ๋๋ก ์ ํํ ์ ์๊ณ ์ด ์ค๋ ๋๋ ์ค๋น ์ํ์ด๋ฉฐ ์ ์ฉํ ์์ ์ ์ํํ๋ค.
- ๋ณ๋ ฌ์ฒ๋ฆฌ (parallelism) :
26.2 ์์ : ์ค๋ ๋ ์์ฑ
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include "common.h"
#include "common_threads.h"
void *mythread(void *arg) {
printf("%s\n", (char *) arg);
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t p1, p2;
int rc;
printf("main: begin\n");
Pthread_create(&p1, NULL, mythread, "A");
Pthread_create(&p2, NULL, mythread, "B");
// join waits for the threads to finish
Pthread_join(p1, NULL);
Pthread_join(p2, NULL);
printf("main: end\n");
return 0;
}
- ํจ์ ํธ์ถ์ฒ๋ผ ์ค๋ ๋๋ฅผ ์์ฑํ๊ธฐ๋ ํ๋ค.
- ํจ์ํธ์ถ์์๋ ํจ์์คํํ์ ํธ์ถ์์๊ฒ ๋ฆฌํดํ๋ ๋ฐ๋ฉด์ ์ค๋ ๋์ ์์ฑ์์๋ ์คํํ ๋ช ๋ น์ด๋ค์ ๊ฐ๊ณ ์๋ ์๋ก์ด ์ค๋ ๋๊ฐ ์์ฑ๋๊ณ ์์ฑ๋ ์ค๋ ๋๋ ํธ์ถ์์๋ ๋ณ๊ฐ๋ก ์คํ๋๋ค.
- ์ค๋ ๋ ์์ฑํจ์๊ฐ ๋ฆฌํด๋๊ธฐ ์ ์ ์ค๋ ๋๊ฐ ์คํ ๋ ์ ๋ ์๊ณ , ๊ทธ๋ณด๋ค ์ดํ์ ์คํ ๋ ์ ์๋ค.
- ๋ค์์ ์คํ๋ ์ค๋ ๋๋ ์ค์ผ์ค๋ฌ์ ์ํด ๊ฒฐ์ ๋๋ค.
- ์ด ์์ ์์ ์ ์ ์๋ฏ ์ค๋ ๋๋ ์ผ์ ๋ณต์กํ๊ฒ ๋ง๋ ๋ค.
26.3 ํจ์ฌ ๋ ์ด๋ ค์ด ์ด์ : ๋ฐ์ดํฐ ๊ณต์
#include <stdio.h>
#include <pthread.h>
#include "common.h"
#include "common_threads.h"
static volatile int counter = 0;
// mythread()
// Simply adds 1 to counter repeatedly, in a loop
// No, this is not how you would add 10,000,000 to
// a counter, but it shows the problem nicely.
void *mythread(void *arg) {
printf("%s: begin\n", (char *) arg);
int i;
for (i = 0; i < 1e7; i++) {
counter = counter + 1;
}
printf("%s: done\n", (char *) arg);
return NULL;
}
// main()
// Just launches two threads (pthread_create)
// and then waits for them (pthread_join)
int main(int argc, char *argv[]) {
pthread_t p1, p2;
printf("main: begin (counter = %d)\n", counter);
Pthread_create(&p1, NULL, mythread, "A");
Pthread_create(&p2, NULL, mythread, "B");
// join waits for the threads to finish
Pthread_join(p1, NULL);
Pthread_join(p2, NULL);
printf("main: done with both (counter = %d)\n", counter);
return 0;
}
- ์ด ํ๋ก๊ทธ๋จ์ ๋จ์ผ ํ๋ก์ธ์๋๋ผ๋ ๊ธฐ๋ํ๋๋ก ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋์ง ์๋๋ค.
26.4 ๋ฌธ์ ์ ํต์ฌ: ์ ์ด ์๋ ์ค์ผ์ค๋ง
- ์์ฝํ๋ฉด t1์ด ๊ฐ์ ์ฝ๊ณ , ์ ์ฅํ๊ธฐ ์ง์ ์ ์ธํฐ๋ฝํธ, t2๋ก ์ ํ, 51๋ก ์ ์ ์ํ, ์ธํฐ๋ฝํธ, t1์ด ์์ ์ ์ด์ด์ํ๋ค๋ณด๋ 51์ ๋ค์ ๋ฐ์..
- ์ด๋ฌํ ์ํฉ ์ฆ ๋ช ๋ น์ด์ ์คํ ์์์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง๋ ์ํฉ์ ๊ฒฝ์์กฐ๊ฑด์ด๋ผ๊ณ ํ๋ค. (race condition, data race)
- ์ด๋ฌํ ๊ฒฝ์ฐ ๋น๊ฒฐ์ ์ ์ธ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ๋ค (indeterminate)
- ๊ทธ๋ฆฌ๊ณ ๋ฉํฐ์ค๋ ๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์คํํ ๋ ๊ฒฝ์์กฐ๊ฑด์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ์ฝ๋ ๋ถ๋ถ์ ์๊ณ ์์ญ(critical section)์ด๋ผ๊ณ ํ๋ค. ๊ณต์ ๋ณ์/์์์ ์ ๊ทผํ๊ณ ํ๋ ์ด์์ ์ค๋ ๋์์ ๋์์ ์คํ๋๋ฉด ์๋๋ ์ฝ๋
- ์ด๋ฌํ ์ฝ๋์์ ํ์ํ๊ฒ์ ์ํธ ๋ฐฐ์ ์ด๋ค. ์ด ์์ฑ์ ํ๋์ ์ค๋ ๋๊ฐ ์๊ณ ์์ญ ๋ด์ ์ฝ๋๋ฅผ ์คํ์ค์ผ ๋๋ ๋ค๋ฅธ์ค๋ ๋๊ฐ ์คํํ ์ ์๋๋ก ๋ณด์ฅํด์ค๋ค.
- ๊ทธ๋ฆฌ๊ณ ์์์ฑ์ด๋ผ๋ ๊ฒ์ ์ ๋ถ ์๋๋ฉด ์ ๋ฌด ์ฆ ๋ชจ๋ ์คํ๋๊ฑฐ๋, ์ค๊ฐ ์ํ๊ฐ ์๋๋ก ๋ชจ๋ ์คํ๋์ง ์์์ผ ํ๋ค๋ ์๋ฏธ์ด๋ค. (atomic)
26.5 ์์์ฑ์ ๋ํ ๋ฐ๋
- ์๊ณ ์์ญ ๋ฌธ์ ์ ๋ํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ค ํ๋๋ก ๊ฐ๋ ฅํ ๋ช ๋ น์ด ํ ๊ฐ๋ก ์๋ํ ๋์์ ์ํํ์ฌ, ์ธํฐ๋ฝํธ ๋ฐ์ ๊ฐ๋ฅ์ฑ์ ์์ฒ์ ์ผ๋ก ์ฐจ๋จํ๋ ๊ฒ์ด๋ค.
mov 0x8049alc, % e a x
add $0x1, &eax
mov seax, 0x8049alc
- ์์ ์ผ๋ จ์ ๋ช
๋ น์ด๋ฅผ ์ด๋ฌํ
memory-add 0x8049alc, $0x1
ํ๋์ ๋ฌธ์ฅ์ผ๋ก ๊ตฌ๋ถํด์ ์์์ฑ์ ๋๊ฒ ํ๋ค๋ฉด ๊ฐ๋ฅํ๊ธฐ๋ ํ๋ค. - ํ์ง๋ง ํ์ค์ ์ผ๋ก ์ด๋ ค์ด ๋ถ๋ถ์ด ๋ง๋ค.
- ์๋ฅผ๋ค์ด ๋ณํ์ฑ์ ๊ฐ์ง๋ B-tree๋ฅผ ๋ง๋๋ ์ค์ด๋ผ๊ณ ํ์ ๋, ์์์ ์ผ๋ก B-tree๋ฅผ ๊ฐฑ์ ํ๋
์ด์ ๋ธ๋ฆฌ์ด
๋ฅผ ์ํด์ผ ํ ๊น? ๊ทธ๋ฌ๋ฉด ์ด์ ๋ธ๋ฆฌ์ด๋ ์ ํ ์ผ๋ฐ์ ์ด์ง ์๊ฒ ๋๋ค. - ๋ฐ๋ผ์ ์ฐ๋ฆฌ๊ฐ ํด์ผ ํ ์ผ์ ํ๋์จ์ด์ ๋๊ธฐํ ํจ์ (synchronization primitives)๊ตฌํ์ ํ์ํ ๋ช๊ฐ์ง ์ ์ฉํ ๋ช ๋ น์ด๋ฅผ ์ํ๋ฉด ๋๋ค.
- ์ด ํ๋์จ์ด ์ง์์ ์ฌ์ฉํ๊ณ ์ด์์ฒด์ ์ ๋์์ ๋ฐ์ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง ์๊ณ์์ญ์์ ์คํํ๋๋ก ๊ตฌ์ฑ๋ ๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋จ์ ๋ง๋ค ์ ์๋ค.
26.6 ๋ ๋ค๋ฅธ ๋ฌธ์ : ์๋ ๊ธฐ๋ค๋ฆฌ๊ธฐ
- ๋ ๋ณต์กํด์ง๋ ๊ฒ์ค์ ํ๋๋ ์ค๋ ๋๊ฐ์ ์์๋ ์๊ธธ์ ์๋ค.
- ์๋ฅผ๋ค์ด ํ๋์์ค๋ ๋๊ฐ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์ด๋ค ๋์์ ๋๋ผ ๋ ๊น์ง ๋๊ธฐํด์ผ ํ๋ ์ํฉ๋ ๋น๋ฒํ๊ฒ ๋ฐ์ํ๋ค.
- ํ๋ก์ธ์ค๊ฐ ๋์คํฌ i/o๋ฅผ ์์ฒญํ๊ณ ์๋ต์ด ์ฌ ๋ ๊น์ง ์ ๋ ๊ฒฝ์ฐ๊ฐ ์ข์ ์์ด๋ค.
์ฐธ๊ณ ๋ก ์ด ์ฅ์ ๋ฉํฐ์ค๋ ๋์ ๋ฌธ์ ์ ๋ํ ์ ์์ ์ฉ์ด์ ๋ฆฌ๊ฐ ์ ๋ถ์ธ๋ฐ, ์ฉ์ด์ ๋ฆฌ๋ฅผ ์๋ฌธ๊ณผ ํจ๊ป ๋ค์ํ๋ฉด ์ข์ ๊ฒ ๊ฐ์์ ์๋์ ์ธ์ฉ๋ฌธ์ ๊ฐ์ ธ์๋ค, ๊ฑฐ์ ๋ชจ๋ ์ฉ์ด๋ ๋ค์ต์คํธ๋ผ๊ฐ ์ ์ํ๋ค๊ณ ํ๋ค.
These four terms are so central to concurrent code that we thought it
worth while to call them out explicitly. See some of Dijkstraโs early work
[D65,D68] for more details.
โข A critical section is a piece of code that accesses a shared resource,
usually a variable or data structure.
โข A race condition (or data race [NM92]) arises if multiple threads of
execution enter the critical section at roughly the same time; both
attempt to update the shared data structure, leading to a surprising
(and perhaps undesirable) outcome.
โข An indeterminate program consists of one or more race conditions;
the output of the program varies from run to run, depending on
which threads ran when. The outcome is thus not deterministic,
something we usually expect from computer systems.
โข To avoid these problems, threads should use some kind of mutual
exclusion primitives; doing so guarantees that only a single thread
ever enters a critical section, thus avoiding races, and resulting in
deterministic program outputs
27 ๋ง๊ฐ: ์ค๋ ๋ api
ํต์ฌ ์ง๋ฌธ : ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ์ ์ดํ๋ ๋ฐฉ๋ฒ ์ด์์ฒด์ ๊ฐ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ์ ์ดํ๋ ๋ฐ ์ด๋ค ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์ผ ํ ๊น? ์ด๋ป๊ฒ ์ด ์ธํฐํ์ด์ค๋ฅผ ์ค๊ณํด์ผ ์ฝ๊ณ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์์๊น?
27.1 ์ค๋ ๋ ์์ฑ
#include <pthread.h>
int pthread_create(pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg);
thread
: pthread_t ํ์ ๊ตฌ์กฐ์ฒด์ ํฌ์ธํฐ. ์ด ๊ตฌ์กฐ๊ฐ ์ค๋ ๋์ ์ํธ์์ฉํ๋๋ฐ ์ฐ์ด๊ธฐ๋๋ฌธ์ ์ด๊ธฐํ์ ์ ๋ฌ.attr
: ์ค๋ ๋์ ์์ฑ ์ง์ , ์คํ ํฌ๊ธฐ์ ์ค๋ ๋์ ์ค์ผ์ค๋ง ์ฐ์ ์์์ ๊ฐ์ ์ ๋ณด๋ค*(*start_routine)(void *)
: ์ด ์ค๋ ๋๊ฐ ์คํํ ํจ์, ์์์์๋ void ํจ์๋ฅผ ์ ๋ฌ*arg
: ์คํํ ํจ์์๊ฒ ์ ๋ฌํ ์ธ์.
#include <stdio.h>
#include <pthread.h>
typedef struct {
int a;
int b;
} myarg_t;
void *mythread(void *arg) {
myarg_t *args = (myarg_t *) arg;
printf("%d %d\n", args->a, args->b);
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t p;
myarg_t args = {10, 20};
int rc = pthread_create(&p, NULL, mythread, &args);
if (rc != 0) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
...
}
27.2 ์ค๋ ๋ ์ข ๋ฃ
int pthread_join (pthread_t thread, void **value_ptr);
thread
: ๊ธฐ๋ค๋ฆด ์ค๋ ๋**value_ptr
: ๋ฐํ๊ฐ์ ํฌ์ธํฐ
typedef struct { int a; int b; } myarg_t;
typedef struct { int x; int y; } myret_t;
void *mythread(void *arg) {
myret_t *rvals = Malloc(sizeof(myret_t));
rvals->x = 1;
rvals->y = 2;
return (void *) rvals;
}
int main(int argc, char *argv[]) {
pthread_t p;
myret_t *rvals;
myarg_t args = { 10, 20 };
Pthread_create(&p, NULL, mythread, &args);
Pthread_join(p, (void **) &rvals);
printf("returned %d %d\n", rvals->x, rvals->y);
free(rvals);
return 0;
}
- ํนํ ์ฃผ์ํด์ผํ ๊ฒ์ ์ค๋ ๋์ ๋ฐํ๊ฐ์ ์ค๋ ๋ ์ฝ์คํ์ ํฌ์ธํฐ๋ฅผ ์ ๋ ๋ฐํํ์ง ๋ง๋ผ๋ ๊ฒ์ด๋ค.
์ฌ์ค ์์ ์์๋ค์ ๊ทธ๋ฅ ํ๋ก์์ ํธ์ถ์ ์ฐ๋๊ฒ ๋ซ๋ค. ๊ตณ์ด ์ ๋ ๊ฒ ํ ์ด์ ๊ฐ ์๋ค
- ๋ณดํต ์น์๋ฒ๋ ๊ทธ๋ฅ join์ ๊ฑฐ์ ์์ฐ๊ณ ๋ฉ์ธ์ค๋ ๋๋ฅผ ์ด์ฉํด์ ์ฌ์ฉ์ ์์ฒญ์ ๋ฐ์ ์์ ์์๊ฒ ์ ๋ฌํ๋ ์์ ์ ๋ฌดํํ ํ ๊ฒ
- ๋๋ ์ค์ ๋ณ๋ ฌ์ ์ผ๋ก ์ฒ๋ฆฌํ๋๊ฒฝ์ฐ๋ ์ด๋ ๊ฒ ํ๋๋๊ฐ์ ์ผ๋ง ํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ ์์์ฝ๋๋ผ ํ๋๊ฒ
#include <stdio.h>
#include <pthread.h>
void *mythread(void *arg) {
int id = *(int *)arg;
printf("Thread %d is running\n", id);
return NULL;
}
int main() {
pthread_t threads[3];
int ids[3] = {1, 2, 3};
// ์ฌ๋ฌ ๊ฐ์ ์ฐ๋ ๋ ์์ฑ
for (int i = 0; i < 3; i++) {
pthread_create(&threads[i], NULL, mythread, &ids[i]);
}
// ๋ชจ๋ ์ฐ๋ ๋๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
for (int i = 0; i < 3; i++) {
pthread_join(threads[i], NULL);
}
printf("All threads finished\n");
return 0;
}
27.3 ๋ฝ
- POSIX ์ค๋ ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ ์๋์ฒ๋ผ ์ ๊ณต๋๋ค.
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
- ๋ญ๊ฐ ์๋์ฒ๋ผ ์๊ธด ์ฝ๋๋ฅผ ์๊ฐํ๊ฒ ์ง๋ง ์ผ๋ถ ํ๋ฆฐ์ ์ด ์๋ค.
- ๋ค๋ง ๊ธฐ๋ณธ์ ์ผ๋ก
pthread_mutex_lock()
์ด ํธ์ถ๋์์๋ ๋ค๋ฅธ ์ด๋ค ์ค๋ ๋๋ ๋ฝ์ ๊ฐ์ง๊ณ ์์ง ์๋ค๋ฉด ์ด ์ค๋ ๋๊ฐ ๋ฝ์ ์ป์ด ์๊ณ ์์ญ์ ์ง์ ํ๋ค. - ๋ฝ ํ๋์ ์๋ํ๋ ์ค๋ ๋๋ ๋ฝ์ ์ป์ ๋๊น์ง ํธ์ถ์์ ๋ฆฌํดํ์ง ์๋๋ค.
- ๋ฝ์ ํ๋ํ ์ค๋ ๋๋ง ์ธ๋ฝ์ ํธ์ถํด์ผํ๋ค.
pthread_mutex_t lock;
pthread_mutex_lock(&lock);
x = x + 1; // or whatever your critical section is
pthread_mutex_unlock(&lock);
- ์ด์ฝ๋๊ฐ ๋์ํ์ง์๋ ์ด์ ๋ ๋๊ฐ์ง์ด์ง๋ค.
- ์ฒซ๋ฒ์งธ๋ก๋ ์ด๊ธฐํ๋ฅผ ํ์ง ์์๋ค.
- ๋๋ฒ์งธ ๋ฌธ์ ๋ ๋ฝ๊ณผ ์ธ๋ฝ์ ํธ์ถ ํ ๋ ์๋ฌ์ฝ๋๋ฅผ ํ์ธํ์ง ์์๋ค๋ ๊ฒ์ด๋ค.
- ๋ง์ฝ ์กฐ์ฉํ ์คํจํ๋๊ฒฝ์ฐ ์ฌ๋ฌ์ค๋ ๋๊ฐ ์๊ณ์์ญ์ ๋์ ์ง์ ์ด ๊ฐ๋ฅํ๋ค.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t lock;
int x = 0; // ๊ณต์ ์์ (์๊ณ ์์ญ ๋ณดํธ ํ์)
void *mythread(void *arg) {
if (pthread_mutex_lock(&lock) != 0) { // ๋ฝ ํ๋ ์คํจ ์ ์ค๋ฅ ์ฒ๋ฆฌ
perror("pthread_mutex_lock failed");
return NULL;
}
// ์๊ณ ์์ญ (Critical Section)
x = x + 1;
printf("Thread %ld: x = %d\n", pthread_self(), x);
if (pthread_mutex_unlock(&lock) != 0) { // ์ธ๋ฝ ์คํจ ์ ์ค๋ฅ ์ฒ๋ฆฌ
perror("pthread_mutex_unlock failed");
return NULL;
}
return NULL;
}
int main() {
pthread_t t1, t2;
// ๋ฎคํ
์ค ์ด๊ธฐํ (๋ฐํ๊ฐ ์ฒดํฌ)
if (pthread_mutex_init(&lock, NULL) != 0) {
perror("pthread_mutex_init failed");
return 1;
}
// ๋ ๊ฐ์ ์ค๋ ๋ ์์ฑ
pthread_create(&t1, NULL, mythread, NULL);
pthread_create(&t2, NULL, mythread, NULL);
// ์ค๋ ๋ ์ข
๋ฃ ๋๊ธฐ
pthread_join(t1, NULL);
pthread_join(t2, NULL);
// ๋ฎคํ
์ค ์ ๊ฑฐ
pthread_mutex_destroy(&lock);
return 0;
}
- ์์ ์ฝ๋๋ฅผ ์๋์ฒ๋ผ ๊น๋ํ๊ฒ ์ ์งํ๋๋ก!
// Keeps code clean; only use if exit() OK upon failure
void Pthread_mutex_lock(pthread_mutex_t *mutex) {
int rc = pthread_mutex_lock(mutex);
assert(rc == 0);
}
- ์๋ ๋ ๋ฃจํด๋ ์์ง๋ง ์ฌ์ฉํ์ง ์๋ ํธ์ด ๋ซ๋ค.
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
struct timespec *abs_timeout);
27.4 ์ปจ๋์ ๋ณ์
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
- ํ ์ค๋ ๋๊ฐ ๊ณ์ ์งํํ๊ธฐ ์ ์ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ๋ฌด์์ธ๊ฐ๋ฅผ ํด์ผ ํ๋ ๊ฒฝ์ฐ
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Pthread_mutex_lock(&lock);
while (ready == 0)
Pthread_cond_wait(&cond, &lock);
Pthread_mutex_unlock(&lock);
28 ๋ฝ
28.1 ๊ธฐ๋ณธ ๊ฐ๋
- ํ๋ก๊ทธ๋๋จธ๋ค์ ์์ค์ฝ๋์ ์๊ณ์์ญ์ ๋ฝ์ผ๋ก ๋๋ฌ์ ๊ทธ ์๊ณ์์ญ์ด ๋ง์น ํ๋์ ์์ ๋จ์ ๋ช ๋ น์ด์ธ๊ฒ์ฒ๋ผ ์คํ๋๋๋ก ํ๋ค.
lock_t mutex; // some globally-allocated lock 'mutex'
lock(&mutex);
balance = balance + 1;
unlock(&mutex);
- ๋ฝ์ ์ผ์ข
์ ๋ณ์์ด๋ฉฐ, ๋ฝ๋ณ์๋ ๋์ค ํ๋์ ์ํ๋ฅผ ๊ฐ๋๋ค
- ์ฌ์ฉ๊ฐ๋ฅ (available, unlocked, free)
- ์ฌ์ฉ์ค (acquired)
- ๊ทธ๋ฆฌ๊ณ ์๊ณ ์์ญ์์๋ ์ ํํ ํ๋์ ์ค๋ ๋๊ฐ ๋ฝ์ ํ๋ํ ์ํ์ด๋ค
- ๋ฝ ์์ ์์ unlcok()์ผ๋ก ๋ฝ์ ์ฌ์ฉ ๊ฐ๋ฅ์ผ๋ก ๋๋์๊ฐ๋ค.
- ๋ฝ์ ํ๋ก๊ทธ๋๋จธ์๊ฒ ์ค์ผ์ค๋ง์ ๋ํ ์ต์ํ์ ์ ์ด๊ถ์ ์ ๊ณตํ๋ค.
- ํ๋ก๊ทธ๋๋จธ๊ฐ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ์ด์์ฒด์ ๊ฐ ์ ์ดํ๋ค.
- ๋ฝ์ ์ค๋ ๋์ ๋ํ ์ ์ด๊ถ์ ์ผ๋ถ ์ด์ ๋ฐ์ ์ ์๊ฒ ํด์ค๋ค.
28.2 Pthread ๋ฝ
- ์ค๋ ๋๊ฐ์ ์ํธ ๋ฐฐ์ (mutual exclusion)์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ posix ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ฝ์ mutex๋ผ๊ณ ๋ถ๋ฅธ๋ค.
28.3 ๋ฝ์ ๊ตฌํ
- ๋ฝ์ ๋์ ๋ฐฉ์์ ์ดํดํ๊ธฐ๊ฐ ์ฌ์ ๋๋ต์ ์ผ๋ก ์ดํดํ์ ๊ฒ์ด๋ค ๊ทธ๋ ๋ค๋ฉด ์ด๋ป๊ฒ ๋ฝ์ ๋ง๋ค์ด์ผ ํ๋๊ฐ?
ํต์ฌ์ง๋ฌธ : ๋ฝ์ ์ด๋ป๊ฒ ๋ง๋ค๊น? ํจ์จ์ ์ธ ๋ฝ์ ์ด๋ป๊ฒ ๋ง๋ค์ด์ผํ ๊น? ํจ์จ์ ์ธ ๋ฝ์ ๋ฎ์ ๋น์ฉ์ผ๋ก ์ํธ ๋ฐฐ์ ๊ธฐ๋ฒ์ ์ ๊ณตํ๊ณ , ๋ค์์ ๋ค๋ฃฐ ๋ช๊ฐ์ง ์์ฑ๋ค์ ์ถ๊ฐ๋ก ๊ฐ์ ธ์ผ ํ๋ค. ์ด๋ค ํ๋์จ์ด ์ง์ ํน์ ์ด์์ฒด์ ์ง์์ด ํ์ํ ๊น?
28.4 ๋ฝ์ ํ๊ฐ
- ๋ค์๊ณผ ๊ฐ์ ๊ฒ๋ค์ด ๋ฝ์ ํ๊ฐ์์ธ์ด๋ค.
- ์ํธ ๋ฐฐ์ (mutual exclusion)์ ์ ๋๋ก ์ง์ํ๋๊ฐ?
- ๊ณต์ ์ฑ (fairness)๋ ์ค๋ ๋๋ค์ด ๋ฝํ๋์ ๋ํ ๊ณต์ ํ ๊ธฐํ๊ฐ ์ฃผ์ด์ง๋๊ฐ? ๋ฐ๋๋ก starve์ํ๊ฐ ์ผ์ด๋์ง๋ ์๋๊ฐ?
- ์ฑ๋ฅ (performance)๋ ๋ฝ ์ฌ์ฉ ์๊ฐ์ ์ค๋ฒํค๋๋ฅผ ํ๊ฐํด์ผํ๋ค.
- ์ด๊ฑด ์ฌ๋ฌ์ค๋ ๋, ํน์ ๋ฉํฐ cpu๊ฐ์์๋ ํ๊ฐ๋ฅผ ๊ฐ๊ฐ ํด์ผํ๋ค.
28.5 ์ธํฐ๋ฝํธ ์ ์ด
- ์ด์ฐฝ๊ธฐ ๋จ์ผ ํ๋ก์ธ์ค ์์คํ ์์๋ ์ํธ ๋ฐฐ์ ์ง์์ ์ํด ์๊ณ์์ญ ๋ด์์๋ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
void lock() {
DisableInterrupts();
}
void unlock() {
EnableInterrupts();
}
- ๋จ์ํ๋ค, ๊ทธ๋ฆฌ๊ณ ์ดํดํ๊ธฐ ์ฝ๋ค.
- ๋ ธ๋ ฅํ์ง ์์๋ ์ ๋์ํ ๊ฒ์ ์ง์ํ ์ ์๋ค.
- ์๊ณ์์ญ๋ด์ ๋์์ด ์งํ๋๋ ๋์ ์ธํฐ๋ฝํธ๋ฅผ ๋ฌด์ํ ์ ์๋ค๋ฉด, ์๊ณ์์ญ๋ด์ ๋์์ด ์์์ ์ผ๋ก ์ํ๋ ๊ฒ์ ๋ณด์ฅํ ์ ์๋ค.
- ๋จ์ ์ด ๋ง๋ค.
- ์ฒซ ๋ฒ์งธ๋, ์ด ์์ฒญ์ ํ๋ ์ค๋ ๋๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฑ/๋นํ์ฑํ๋ priviledged ์ฐ์ฐ์ ์คํ ํ ์ ์๋๋ก ํ๊ฐํด์ผ ํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ์ด priviledged ๊ถํ์ ํตํด ๋ค๋ฅธ ๊ฒ์ ํ์ง ์๋๋ค๋๊ฒ์ ์ ๋ขฐ ํ ์ ์์ด์ผ ํ๋ค.
- ์๋ฅผ๋ค์ด lock์ ์ป๊ณ ๋ฌดํ๋ฃจํ ํน์ ๋์์ง์ ํด๋ lde์์๋ ์ ์ด๊ถ์ ๋ค์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- ๋ ๋ฒ์งธ๋, ๋ฉํฐํ๋ก์ธ์์์๋ ์ ์ฉ์ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
- ์ฌ๋ฌ ์ค๋ ๋๊ฐ ์ฌ๋ฌ cpu์์ ์คํ์ค์ด๋ผ๋ฉด ๊ฐ ์ค๋ ๋๊ฐ ๋์ผํ ์๊ณ ์์ญ์ ์ง์ ํ๋ ค๊ณ ์๋ํ ์ ์๋ค.
- ํน์ ํ๋ก์ธ์์์์ ์ธํฐ๋ฝํธ ๋นํ์ฑํ๋ ๋ค๋ฅธ ํ๋ก์ธ์ค์์ ์คํ์ค์ธ ํ๋ก๊ทธ๋จ์๋ ์ํฅ์ด ์๋ค.
- ์ธ ๋ฒ์งธ๋, ์ฅ์๊ฐ๋์ ์ธํฐ๋ฝํธ๋ฅผ ์ค์์ง์ํค๋ ๊ฒ์ ์ค์ํ ์ธํฐ๋ฝํธ์ ์์ ์ ๋์น ์ ์๋ค๋ ๊ฒ์ด๋ค.
- ์๋ฅผ ๋ค์ด cpu๊ฐ ์ ์ฅ ์ฅ์น์์ ์ฝ๊ธฐ ์์ฒญ์ ๋ง์น ์ฌ์ค์ ๋ชจ๋ฅด๊ณ ์ง๋๊ฐ๋ค๊ณ ํด๋ณด์.
- ์ด์์ฒด์ ๊ฐ ์ฝ๊ธฐ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ํ๋ก์ธ์ค๋ฅผ ์ด๋ป๊ฒ ๊นจ์ธ๊น?
- ๋ง์ง๋ง์, ์ด ๋ฐฉ๋ฒ์ ๋นํจ์จ์ ์ด๋ผ๋ ๊ฒ์ด๋ค. (์ต์ cpu์์๋ ๋งค์ฐ ๋๋ฆฌ๊ฒ ๋์ํ๋ค.)
- ์ฒซ ๋ฒ์งธ๋, ์ด ์์ฒญ์ ํ๋ ์ค๋ ๋๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฑ/๋นํ์ฑํ๋ priviledged ์ฐ์ฐ์ ์คํ ํ ์ ์๋๋ก ํ๊ฐํด์ผ ํ๋ค.
28.6 ์คํจํ ์๋: ์ค์ง load/store ๋ช ๋ น์ด๋ง ์ฌ์ฉํ๊ธฐ
typedef struct __lock_t { int flag; } lock_t;
void init(lock_t *mutex) {
// 0 -> lock is available, 1 -> held
mutex->flag = 0;
}
void lock(lock_t *mutex) {
while (mutex->flag == 1) // ๋ง์ฝ ์ฌ์ฉ์ค์ด๋ฉด ๊ธฐ๋ค๋ฆฐ๋ค.
; // spin-wait (do nothing)
mutex->flag = 1; // now SET it!
}
void unlock(lock_t *mutex) {
mutex->flag = 0;
}
- ์์ ์ฝ๋๋ ๋๊ฐ์ง ๋ฌธ์ ๊ฐ ์๋ค.
- ๋จผ์ ์ ๋๋ก ๋์ํ๋์ง ์ฌ๋ถ์ด๋ค.
- ๋๊ฐ์ ์ค๋ ๋๊ฐ flag 0์ ๋ณด๊ณ ๊ฐ์ด ์ง์ ํ๋๊ฒ ๊ฐ๋ฅํ๋ค
- ๋๋ฒ์งธ๋ ์ฑ๋ฅ์ด๋ค.
- ๋ฝ์ ๊ธฐ๋ค๋ฆฌ๋๋์ spin-wait์ ํ๋๊ฒ ๋ฝ์ ํด์ ํ ๋ ๊น์ง ์๊ฐ์ ๋ญ๋นํ๋ค.
- ๋จ์ผํ๋ก์ธ์์์๋ ํนํ ๋งค์ฐ ์ํด๊ฐ ํฌ๋ค. ๋ฝ์ ์์ ํ ์ค๋ ๋์กฐ์ฐจ๋ ์คํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- ์ด๊ฑด lock์ ํธ์ถํ ์ค๋ ๋๊ฐ ๊ธฐ๋ค๋ฆฌ๊ธฐ๋๋ฌธ์, ์์ ํ ์ค๋ ๋๋ ์ปจํ ์คํธ ์ค์์น ์ ๊น์ง๋ ๋ญ ํ ์ ๊ฐ ์์
- ๋จผ์ ์ ๋๋ก ๋์ํ๋์ง ์ฌ๋ถ์ด๋ค.
28.7 Test-And-Set์ ์ฌ์ฉํ์ฌ ์๋ํ๋ ์คํ ๋ฝ ๊ตฌํํ๊ธฐ
- ์์์ ๊ต์ฒด๋ผ๊ณ ๋ ์๋ ค์ง ๋ช ๋ น์ด์ด๋ค.
int TestAndSet(int *old_ptr, int new) {
int old = *old_ptr; // fetch old value at old_ptr
*old_ptr = new; // store 'new' into old_ptr
return old; // return the old value
}
- ์ ์ฝ๋์ ๋์ผํ ๋์์ ํ๋ ํ๋์จ์ด ๋ช ๋ น์ด๋ฅผ ์ง์๋ฐ๋๊ฒ (์ค์ c์ฝ๋๊ฐ ์๋)
typedef struct __lock_t {
int flag;
} lock_t;
void init(lock_t *lock) {
// 0: lock is available, 1: lock is held
lock->flag = 0;
}
void lock(lock_t *lock) {
while (TestAndSet(&lock->flag, 1) == 1)
; // spin-wait (do nothing)
}
void unlock(lock_t *lock) {
lock->flag = 0;
}
- ์ฒซ๋ฒ์งธ๋ก
- ์ฒ์ ์ค๋ ๋๊ฐ lock()์ ํธ์ถํ๊ณ ๋ค๋ฅธ ์ด๋ค ์ค๋ ๋๋ ๋ฝ์ ๋ณด์ ํ์ง ์๋๋ค๋ฉด
- ํ์ฌ์ flag =0์ด๋ผ๋ฉด,
- ์ด ์ค๋ ๋๊ฐ TestAndSet(flag, 1)์ ํธ์ถํ๋ฉด ์ด ๋ฃจํด์ flag์ ์ด์ ๊ฐ์ธ 0์ ๋ฐํํ๋ค.
- flag๊ฐ์ ๊ฒ์ฌํ ์ค๋ ๋๋ while๋ฌธ์์ ํ์ ํ์ง ์๊ณ ๋ฝ์ ํ๋ํ๋ค.
- ๋ ๋ฒ์งธ๋
- ์ฒ์ ์ค๋ ๋๊ฐ ๋ฝ์ ํ๋ํ์ฌ flag๊ฐ์ด 1์ธ์ํ์ด๋ค.
- ๋๋ฒ์งธ ์ค๋ ๋๊ฐ lock์ ํธ์ถํ๋ฉด ์ฒซ ์ค๋ ๋๊ฐ ๋ฐํํ ๋๊น์ง while๋ฌธ์ ๋ฐ๋ณตํ๋ค.
์ฃผ์ํ ์ ์ ์ ์ ํ ์ค์ผ์ค๋ฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.(preemptive scheduler) ๊ทธ๋ ์ง ์์ผ๋ฉด spin while loop๊ฐ ์์ํ ๋ ์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
28.8 ์คํ ๋ฝ ํ๊ฐ
- ๋จ์ผ cpu์ ๊ฒฝ์ฐ๋ ์ค๋ฒํค๋๊ฐ ์๋นํ ํฌ๋ค.
- ์๊ณ์์ญ๋ด์์ ๋ฝ์ ๊ฐ๊ณ ์๋ ์ค๋ ๋๊ฐ ์ ์ ๋ ๊ฒฝ์ฐ, N-1๊ฐ์ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ์๋ค๊ณ ๊ฐ์ ํ ๋ ์ค์ผ์ค๋ฌ๊ฐ ๋ฝ์ ํ๋ํ๋ ค๋ ๋ค๋ฅด ์ค๋ ๋๋ฅผ ๊นจ์ฐ๊ณ ๋๊ธฐํ๋ฉด์ ์๊ฐ์ ๋ญ๋น ํ ์ ์๋ค.
- ๋ฐ๋ฉด์ cpu๊ฐ ์ฌ๋ฌ๊ฐ์ธ ๊ฒฝ์ฐ ์คํ๋ฝ์ ๊ฝค ํฉ๋ฆฌ์ ์ผ๋ก ๋์ํ๋ค.
- ๋ฌผ๋ก ๋๊ธฐ๋ ์์ง๋ง, ๋ฝ์ ์ ์ ํ cpu์ ์์ ์ด ๋๊ธฐ์ง ์์ ๊ฒ ์ด๊ธฐ ๋๋ฌธ์ ๊ธ๋ฐฉ๊ธ๋ฐฉ ๋ฝ์ด ๋์ด๊ฐ๊ฒ์ด๋ค.
28.9 Compare-And-Swap
int CompareAndSwap(int *ptr, int expected, int new) {
int original = *ptr;
if (original == expected)
*ptr = new;
return original;
}
- ptr์ด ๊ฐ๋ฆฌํค๊ณ ์๋ ์ฃผ์์ ๊ฐ์ด expected์ ์ผ์นํ๋์ง ๊ฒ์ฌํ๋๊ฒ์ด๋ค.
- ์ผ์นํ๋ค๋ฉด ์ฃผ์์ ๊ฐ์ ์๋ก์ด ๊ฐ์ผ๋ก ๋ณ๊ฒฝํ๋ค.
- ๋ง์ฝ ๋ถ์ผ์นํ๋ค๋ฉด ์๋ฌด๊ฒ๋ ํ์ง ์๋๋ค.
- ์๋์ ๋ฉ๋ชจ๋ฆฌ ๊ฐ์ ๋ฐํํ์ฌ ํธ์ถํ ์ฝ๋์ ๋ฝ ํ๋ ์ฌ๋ถ๋ฅผ ์ ์ ์๋๋กํ๋ค.
28.11 Fetch-And-Add
int FetchAndAdd(int *ptr) {
int old = *ptr;
*ptr = old + 1;
return old;
}
typedef struct __lock_t {
int ticket;
int turn;
} lock_t;
void lock_init(lock_t *lock) {
lock->ticket = 0;
lock->turn = 0;
}
void lock(lock_t *lock) {
int myturn = FetchAndAdd(&lock->ticket);
while (lock->turn != myturn)
; // spin
}
void unlock(lock_t *lock) {
lock->turn = lock->turn + 1;
}
- ์ค์ผ์ค๋ง์ด ๊ฐ๋ฅํ๋๋ก ํ ๋ฐฉ๋ฒ
28.12 ์์ฝ: ๊ณผ๋ํ ์คํ
ํต์ฌ์ง๋ฌธ: ํ์ ์ ๋ญ๋น์ด๋ค. ํ์ ์ ํผํ๋ ๋ฐฉ๋ฒ์ด ๋ฌด์์ด ์์๊น?
28.13 ๊ฐ๋จํ ์ ๊ทผ๋ฒ: ์กฐ๊ฑด ์๋ ์๋ณด!
void init() {
flag = 0;
}
void lock() {
while (TestAndSet(&flag, 1) == 1)
yield(); // give up the CPU
}
void unlock() {
flag = 0;
}
- ๊ฐ๋จํ๊ณ ์ข์ ์ ๊ทผ๋ฐฉ์์ด์ง๋ง, ์ปจํ ์คํธ ์ค์์น ๋น์ฉ๋ ์๋นํ๋ค.
28.14 ํ์ ์ฌ์ฉ: ์คํ ๋์ ์ ์๊ธฐ
- ์์ ์ ๊ทผ๋ฒ๋ค์ ์ง๋์น๊ฒ ์ด์ ์์กดํ๊ณ ์๋ค.
- ์ด๋ฒ์๋ ํ๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋ค.
typedef struct __lock_t {
int flag;
int guard;
queue_t *q;
} lock_t;
void lock_init(lock_t *m) {
m->flag = 0;
m->guard = 0;
queue_init(m->q);
}
void lock(lock_t *m) {
while (TestAndSet(&m->guard, 1) == 1)
; // acquire guard lock by spinning
if (m->flag == 0) {
m->flag = 1; // lock is acquired
m->guard = 0;
} else {
queue_add(m->q, gettid());
m->guard = 0;
park();
}
}
void unlock(lock_t *m) {
while (TestAndSet(&m->guard, 1) == 1)
; // acquire guard lock by spinning
if (queue_empty(m->q))
m->flag = 0; // let go of lock; no one wants it
else
unpark(queue_remove(m->q)); // hold lock (for next thread!)
m->guard = 0;
}
park()
,unpark(thread)
๋ ๊ฐ๊ฐ ํธ์ถํ ์ค๋ ๋ ํน์, ์๊ท๋จผํธ๋ก ๋๊ธด ์ค๋ ๋๋ฅผ ์ฌ์ฐ๊ณ ๊นจ์ฐ๋ ํจ์์ด๋ค.- ๊ฒฝ์๋ฐ์ ํ๋ํ์ ๋ค ๋นผ๊ณ ๋ค ํ์๋ฃ๊ณ , ๊ทธ๋์ ๋ฝ ํ๋์ฌ๋ถ๋ฅผ ๋๊ตฐ๊ฐ ํ๋ํ๋ค๊ณ ์ค์ ํด๋๊ณ , ํ๊ฐ ๋น์์ง๊ณ ์ธ๋ฝํด์ผํ๋ ๋๊ตฐ๊ฐ๊ฐ ๊ทธ์ฌ์์ผ flag๋ฅผ 0์ผ๋ก ๋๋๋ฆฐ๋ค
- ๋ฌธ์ ๋ ์ฌ๊ธฐ๋ ๊ฒฝ์์กฐ๊ฑด์ด ์๋ค๋๊ฑด๋ฐ (park()๋ฅผ ํธ์ถํ๊ธฐ ์ง์ vs ์ ์ ์ค์ธ ๋ฝ์ ํด์ ํ๋๊ฒฝ์ฐ)
- ์ด๋ฌ๋ฉด ๋ฝ์ ํด์ ๋๊ณ ์ ์ ํ ์ค๋ ๋๊ฐ์์ด์ ๊นจ์์ค ๋ฐฉ๋ฒ์ด ์๋ค.
- Solaris๋ ์ด ๋ฌธ์ ๋ฅผ setPark()๋ฅผ ํตํด์ ํด๊ฒฐํ๋๋ฐ
- ์ด ๋ฃจํด์ ์ค๋ ๋๊ฐ ํ์ฌ park()ํธ์ถ ์ง์ ์ด๋ผ๋๊ฒ์ผ ํ์ํ๋ค. ๋ง์ฝ ๊ทธ๋ ์ธํฐ๋ฝํธ๊ฐ ์คํ๋์ด park()๊ฐ ํธ์ถ๋๊ธฐ ์ ์ ๋ค๋ฅธ ์ค๋ ๋๊ฐ unpark()๋ฅผ ๋จผ์ ํธ์ถํ๋ค๋ฉด ๋ธ๋ญ๋๋๋์ ๋ฐ๋ก ๋ฆฌํด๋๋ค.
} else {
queue_add(m->q, gettid());
setpark(); // ์๊ธฐ
m->guard = 0;
park();
}
29 ๋ฝ ๊ธฐ๋ฐ์ ๋ณํ ์๋ฃ ๊ตฌ์กฐ
๋ฒ์ฉ ์๋ฃ ๊ตฌ์กฐ์์ ๋ฝ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณธ๋ค. ์๋ฃ ๊ตฌ์กฐ์ ๋ฝ์ ์ถ๊ฐํ๋ฉด ํด๋น ์๋ฃ ๊ตฌ์กฐ๋ฅผ ๊ฒฝ์์กฐ๊ฑด์ผ๋ก๋ถํฐ thread safeํ ์๋ฃ๊ตฌ์กฐ๋ก ๋ง๋ค ์ ์๋ค.
ํต์ฌ ์ง๋ฌธ: ์ง๋ฃ๊ตฌ์กฐ์ ๋ฝ์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ ํน์ ์๋ฃ๊ตฌ์กฐ๊ฐ ์ฃผ์ด์ก์ ๋, ์ด๋ค ๋ฐฉ์์ผ๋ก ๋ฝ์ ์ถ๊ฐํด์ผ ๊ทธ ์๋ฃ๊ตฌ์กฐ๊ฐ ์ ํํ๊ฒ ๋์ํ๊ฒ ๋ง๋ค ์ ์์๊น?
29.1 Concurrent Counters
- ์นด์ดํฐ๋ ๊ฐ์ฅ ๊ฐ๋จํ ์๋ฃ๊ตฌ์กฐ์ด๊ณ , ๋ณดํธ์ ์ด๋ฉฐ, ์ธํฐํ์ด์ค๊ฐ ๊ฐ๋จํ๋ค. ๊ฐ๋จํ์ง๋ง, ํ์ฅ์ฑ์ด ์๋ค.
typedef struct __counter_t {
int value;
} counter_t;
void init(counter_t *c) {
c->value = 0;
}
void increment(counter_t *c) {
c->value++;
}
void decrement(counter_t *c) {
c->value--;
}
int get(counter_t *c) {
return c->value;
}
- ์ผ๋จ ์ด๋ ๊ฒ ๊ตฌํํ๋ฉด thread safaํ๊ฒ ๋ง๋ค์ ์๋ค.
typedef struct __counter_t {
int value;
pthread_mutex_t lock;
} counter_t;
void init(counter_t *c) {
c->value = 0;
pthread_mutex_init(&c->lock, NULL);
}
void increment(counter_t *c) {
pthread_mutex_lock(&c->lock);
c->value++;
pthread_mutex_unlock(&c->lock);
}
void decrement(counter_t *c) {
pthread_mutex_lock(&c->lock);
c->value--;
pthread_mutex_unlock(&c->lock);
}
int get(counter_t *c) {
pthread_mutex_lock(&c->lock);
int rc = c->value;
pthread_mutex_unlock(&c->lock);
return rc;
}
- ์ด์ํ์์๋ ๊ฐ๋จํ๊ณ ์ ํํ๊ฒ ๋์ํ์ง๋ง, ์ฑ๋ฅ์ด ๋ฌธ์ ๋ค.
- ์ ์์ ํ
์คํธ์์ ์นด์ดํธ 100๋ง๋ฒ ๊ณ์ฐํ๋๋ฐ
- ์ฑ๊ธ์ค๋ ๋๋ 0.03์ด
- ๋๊ฐ์ ์ค๋ ๋๋ 5์ด ์ด์์ด ๊ฑธ๋ ธ๋ค๊ณ ํ๋ค. (โฆ)
- ์๋ฒฝํ ํ์ฅ์ฑ์ด๋ผ๋ ๊ฒ์ด๋ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ๋ค
- ์๋ฒฝํ ํ์ ์ฑ์ ๋ฌ์ฑํ๋ค๋ฉด ์ค๋ ๋์ ๊ฐฏ์๋งํผ ๋ฐ๋น๋ก๋ก ์๊ฐ์ด ์ค์ด๋ค์์ด์ผํ๋ค.
- ํน์ 200๋ง๋ฒ์ ์งํํ์๋, ๋์ผํ๊ฒ 0.03์ด๊ฐ ๊ฑธ๋ฆฌ๊ฑฐ๋
- ์ ์์ ํ
์คํธ์์ ์นด์ดํธ 100๋ง๋ฒ ๊ณ์ฐํ๋๋ฐ
ํ์ฅ์ฑ ์๋ ์นด์ดํ
- ๊ทธ๋์ ๊ทผ์ฌ ์นด์ดํฐ (approximate counter)๋ผ๊ณ ๋ถ๋ฆฌ๋ ๊ธฐ๋ฒ์ ์ฌ์ฉํ๋ค๊ณ ํ๋ค.
- ๊ธฐ๋ณธ ๊ฐ๋ ์ ์ค๋ ๋ ๋ก์ปฌํ ์ง์ญ ์นด์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ๊ฒฝ์์์ด ์ฆ๊ฐ์ํค๊ณ , ์ด๊ฑด ์ง์ญ๋ฝ์ ์ํด์๋ง ๋ณดํธํ๋ค.
- ๊ทธ ๋ค์ ์ ์ญ์นด์ดํฐ๊ฐ์ ์ง์ญ์นด์ดํฐ๊ฐ์ผ๋ก ๊ฐฑ์ ํ๊ณ ๊ทธ์์ ์ ์ง์ญ์นด์ดํฐ ๊ฐ์ 0์ผ๋ก ์ด๊ธฐํํ๋ค.
- ์ง์ญ์์ ์ ์ญ์ผ๋ก ๊ฐ์ ์ ๋ฌํ๋ ๋น๋๋ S๊ฐ์ ์ํด์ ์ค์ ๋๋ค.
- S๊ฐ์ด ์์์๋ก (๊ฐฑ์ ๋น๋๋ ์ปค์ง์๋ก) ์นด์ดํฐ์ ํ์ฅ์ฑ์ด ์์ด์ง๋ฉฐ,
- S๊ฐ์ด ํด์๋ก (๊ฐฑ์ ๋น์กฐ๋ ์์์ง์๋ก) ์ ์ญ์นด์ดํฐ๊ฐ์ด ์ค์ ์นด์ดํฐ ๊ฐ๊ณผ ์ผ์นํ์ง ์์ ํ๋ฅ ์ด ์ปค์ง๋ค.
typedef struct __counter_t {
int global; // global count
pthread_mutex_t glock; // global lock
int local[NUMCPUS]; // per-CPU count
pthread_mutex_t llock[NUMCPUS]; // ... and locks
int threshold; // update frequency
} counter_t;
// init: record threshold, init locks, init values
// of all local counts and global count
void init(counter_t *c, int threshold) {
c->threshold = threshold;
c->global = 0;
pthread_mutex_init(&c->glock, NULL);
for (int i = 0; i < NUMCPUS; i++) {
c->local[i] = 0;
pthread_mutex_init(&c->llock[i], NULL);
}
}
// update: usually, just grab local lock and update
// local amount; once local count has risen โthresholdโ,
// grab global lock and transfer local values to it
void update(counter_t *c, int threadID, int amt) {
int cpu = threadID % NUMCPUS;
pthread_mutex_lock(&c->llock[cpu]);
c->local[cpu] += amt;
if (c->local[cpu] >= c->threshold) {
// transfer to global (assumes amt>0)
pthread_mutex_lock(&c->glock);
c->global += c->local[cpu];
pthread_mutex_unlock(&c->glock);
c->local[cpu] = 0;
}
pthread_mutex_unlock(&c->llock[cpu]);
}
// get: just return global amount (approximate)
int get(counter_t *c) {
pthread_mutex_lock(&c->glock);
int val = c->global;
pthread_mutex_unlock(&c->glock);
return val; // only approximate!
}
29.2 Concurrent Linked List
// basic node structure
typedef struct __node_t {
int key;
struct __node_t *next;
} node_t;
// basic list structure (one used per list)
typedef struct __list_t {
node_t *head;
pthread_mutex_t lock;
} list_t;
void List_Init(list_t *L) {
L->head = NULL;
pthread_mutex_init(&L->lock, NULL);
}
int List_Insert(list_t *L, int key) {
pthread_mutex_lock(&L->lock);
node_t *new = malloc(sizeof(node_t));
if (new == NULL) {
perror("malloc");
pthread_mutex_unlock(&L->lock);
return -1; // fail
}
new->key = key;
new->next = L->head;
L->head = new;
pthread_mutex_unlock(&L->lock);
return 0; // success
}
int List_Lookup(list_t *L, int key) {
pthread_mutex_lock(&L->lock);
node_t *curr = L->head;
while (curr) {
if (curr->key == key) {
pthread_mutex_unlock(&L->lock);
return 0; // success
}
curr = curr->next;
}
pthread_mutex_unlock(&L->lock);
return -1; // failure
}
- ๋ง์ฐฌ๊ฐ์ง๋ก ํ์ฅ์ฑ์ด ์ข์ง ์๋ค๋ ๋ฌธ์ ๊ฐ ์๋ค.
- ์ด๊ฑด ์ ๋ง ํ์ํ ๋ถ๋ถ๋ง ๋ฝ์ ๊ฑฐ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ๋ค.
void List_Init(list_t *L) {
L->head = NULL;
pthread_mutex_init(&L->lock, NULL);
}
void List_Insert(list_t *L, int key) {
// synchronization not needed before allocation
node_t *new = malloc(sizeof(node_t));
if (new == NULL) {
perror("malloc");
return;
}
new->key = key;
// just lock critical section
pthread_mutex_lock(&L->lock);
new->next = L->head;
L->head = new;
pthread_mutex_unlock(&L->lock);
}
int List_Lookup(list_t *L, int key) {
int rv = -1;
pthread_mutex_lock(&L->lock);
node_t *curr = L->head;
while (curr) {
if (curr->key == key) {
rv = 0;
break;
}
curr = curr->next;
}
pthread_mutex_unlock(&L->lock);
return rv; // now both success and failure
}
29.3 Concurrent Queue
- ๊ผญ ํ์ํ ๋ถ๋ถ์๋ง ๋ฝ์ ๊ฑธ์ด์ ๋ถํ๋ฅผ ์ค์ธ ์ข์ ์ต์ ํ ์์
typedef struct __node_t {
int value;
struct __node_t *next;
} node_t;
typedef struct __queue_t {
node_t *head;
node_t *tail;
pthread_mutex_t head_lock, tail_lock;
} queue_t;
void Queue_Init(queue_t *q) {
node_t *tmp = malloc(sizeof(node_t));
tmp->next = NULL;
q->head = q->tail = tmp;
pthread_mutex_init(&q->head_lock, NULL);
pthread_mutex_init(&q->tail_lock, NULL);
}
void Queue_Enqueue(queue_t *q, int value) {
node_t *tmp = malloc(sizeof(node_t));
assert(tmp != NULL);
tmp->value = value;
tmp->next = NULL;
pthread_mutex_lock(&q->tail_lock);
q->tail->next = tmp;
q->tail = tmp;
pthread_mutex_unlock(&q->tail_lock);
}
int Queue_Dequeue(queue_t *q, int *value) {
pthread_mutex_lock(&q->head_lock);
node_t *tmp = q->head;
node_t *new_head = tmp->next;
if (new_head == NULL) {
pthread_mutex_unlock(&q->head_lock);
return -1; // queue was empty
}
*value = new_head->value;
q->head = new_head;
pthread_mutex_unlock(&q->head_lock);
free(tmp);
return 0;
}
30 Condition Variables
- ๋ฝ ์ด์ธ์๋ ๋ณํ ํ๋ก๊ทธ๋จ์ ์ ์ํ ์ ์๋ ๋ค๋ฅธ ๊ธฐ๋ฒ๋ค์ด ์กด์ฌํ๋ค.
- ์ค๋ ๋๊ฐ ์คํ์ ๊ณ์ํ๊ธฐ ์ ์ ํน์ ์กฐ๊ฑด์ ๋ง์กฑ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ด ์๋ค.
void *child(void *arg) {
printf("child\n");
// XXX how to indicate we are done?
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t c;
pthread_create(&c, NULL, child, NULL); // create child
// XXX how to wait for child?
printf("parent: end\n");
return 0;
}
- ์ฐ๋ฆฌ๊ฐ ์ํ๋๊ฒ
parent: begin
child
parent: end
- ๊ณต์ ๋ณ์๋ฅผ ์ธ ์ ์๊ธฐ๋ ํ์ง๋ง, ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ๊ฐ ํ์ ์ ํด์ผํ๊ธฐ๋๋ฌธ์ ํจ์จ์ ์ด์ง ์๋ค.
30.1 ์ปจ๋์ ๋ณ์์ ๊ฐ๋ ๊ณผ ๊ด๋ จ ๋ฃจํด
- ์ปจ๋์ ๋ณ์๋ ์ผ์กด์ ํ ์๋ฃ ๊ตฌ์กฐ์ด๋ค.
- ์ด๋ค ์ํ๊ฐ ์ํ๋ ๊ฒ๊ณผ ๋ค๋ฅผ๋ ์กฐ๊ฑด์ด ๋ง์กฑ๋๊ธฐ๋ฅผ ๋๊ธฐํ๋ ํ์ด๋ค.
int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
void thr_exit() {
Pthread_mutex_lock(&m);
done = 1;
Pthread_cond_signal(&c);
Pthread_mutex_unlock(&m);
}
void *child(void *arg) {
printf("child\n");
thr_exit();
return NULL;
}
void thr_join() {
Pthread_mutex_lock(&m);
while (done == 0)
Pthread_cond_wait(&c, &m);
Pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t p;
Pthread_create(&p, NULL, child, NULL);
thr_join();
printf("parent: end\n");
return 0;
}
- pthread_cond_t c; ๋ผ๊ณ ์จ์ c๊ฐ ์ปจ๋์ ๋ณ์๊ฐ ๋๋๋ก ํ๋ค.
- ์ปจ๋์
๋ณ์์๋ wait()๊ณผ signal()์ด๋ผ๋ ๋๊ฐ์ ์ฐ์ฐ์ด ์๋ค.
- wait์ ์ค๋ ๋๊ฐ ์ค์ค๋ก๋ฅผ ์ ์ฌ์ฐ๊ธฐ ์ํด์
- signal์ ์กฐ๊ฑด์ด ๋ง์กฑ๋๊ธฐ๋ฅผ ๋๊ธฐํ๋ฉฐ ์ ์๊ณ ์๋ ์ค๋ ๋๋ฅผ ๊นจ์ธ๋ ํธ์ถํ๋ค.
pthread_cond_wait (pthread_cond_t *c, thread_mutex_t *m) ;
pthread_cond_signal (pthread_cond_t *c) ;
- ๊ณผ์ ์ ๋ช
ํํ ๊ธฐ์ตํด์ผ ํ๋ค.
- ์ฌ๋ฆฝ์์ ๊นจ์ด๋ ํ๋ก์ธ์ค๋ ๋ฆฌํดํ๊ธฐ ์ ์ ๋ฝ์ ์ฌํ๋ํด์ผํ๋ค.
- ์๊ทธ๋์ ๋ฐ์์ ๋๊ธฐ์ํ์์ ๊นจ์ด๋ฌ๋๋ผ๋ ๋ฝํ๋์ ์คํจํ๋ฉด ๋ค์ ์ฌ๋ฆฝํ๋ค.
30.2 ์์ฐ์/์๋น์ (์ ํ๋ฒํผ) ๋ฌธ์
- ์์ฃผ ์ฌ์ฉ๋๋ ํจํด
- ์์ฐ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด ๋ฒํผ์ ๋ฃ๊ณ , ์๋น์๋ ๋ฒํผ์์ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด์ด ์ฌ์ฉํ๋ค.
- ์น์๋ฒ๋ฑ ์์ฒญ ๋ง์ด ์ฌ์ฉ๋๋ ํจํด
- ์ ๋์ค๋ ๋ง์ฐฌ๊ฐ์ง์ด๋ค.
grep foo file.txt | wc -1
- grep์ด ์์ฐ์ wc๊ฐ ์๋น์
- ๋ฌธ์ ๋ ์ ํ ๋ฒํผ๊ฐ ๊ณต์ ์์์ด๋ผ๋ ๊ฒ์ด๋ค, ๊ฒฝ์ ์กฐ๊ฑด์ ๋ฐ์์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋๊ธฐํ๊ธฐ ํ์ํ๋ค.
int buffer;
int count = 0; // initially, empty
void put(int value) {
assert(count == 0);
count = 1;
buffer = value;
}
int get() {
assert(count == 1);
count = 0;
return buffer;
}
- ๊ฐ๋จํ๋ค, ์์ฐ์๋ ๋ฒํผ๊ฐ ๋น์ด์๋ค๋ฉด (count = 0) ๋ฃ๊ณ ,
- ์๋น์๋ ๋ฒํผ๊ฐ ์ฐจ์์ผ๋ฉด (count = 1) ๋บ๋ค.
void *producer(void *arg) {
int i;
int loops = (int) arg;
for (i = 0; i < loops; i++) {
put(i);
}
}
void *consumer(void *arg) {
while (1) {
int tmp = get();
printf("%d\n", tmp);
}
}
- ์ด๋ฐ ์ฝ๋๋ ์ ๋๋ก ๋์ํ์ง ์๋๋ค.
- ๊ณต์ ๋ณ์ (count์์ ๊ฒฝ์ ์กฐ๊ฑด์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ด๋ค.)
๋ถ์์ ํ ํด๋ต.
int loops; // must initialize somewhere...
cond_t cond;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
if (count == 1) // p2
Pthread_cond_wait(&cond, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&cond); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
if (count == 0) // c2
Pthread_cond_wait(&cond, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&cond); // c5
Pthread_mutex_unlock(&mutex); // c6
printf("%d\n", tmp);
}
}
- ์ด์ฝ๋๋ ๋์ํ ๊ฒ ๊ฐ์ง๋ง ์ค๋ ๋๊ฐ ๋์ด๋๋ฉด ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
- ์๋น์ ๋จผ์ ์คํ๋๋ค (TC1)
- ๋ฝ์ ํ๋ํ๊ณ (c1) ๋ฒํผ๋ฅผ ์๋นํ ์ ์๋์ง ๊ฒ์ฌํ๋ค(c2)
- ๋น์ด์์์ ํ์ธํ๊ณ ๋๊ธฐํ๋ฉฐ (c3) ๋ฝ์ ํด์ ํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ์์ฐ์๊ฐ ์คํ๋๋ค.
- ๋ฝ์ ํ๋ํ๊ณ (p1), ๋ฒํผ๊ฐ ๋น์๋์ง ํ์ธํ๋ค (p2)
- ๋น์ด์์์ ํ์ธํ๊ณ ๋ฒํผ๋ฅผ ์ฑ์ด๋ค(p4)
- ๋ฒํผ๊ฐ ๊ฐ๋์ฐผ๋ค๋ ์๊ทธ๋์ ๋ณด๋ธ๋ค (p5)
- ์๋น์๋ ์ค๋น ํ๋ก ์ด๋ํ๋ค.
- ์๋น์๋ ์ค๋น๋์์ง๋ง ์คํ๊ฐ๋ฅํ์ง๋ ์์ ์ํ์ด๋ค.
- ์์ฐ์๋ ์คํ์ ๊ณ์ํ๋ค.
- ๋ฒํผ๊ฐ ์ฐจ์์ผ๋ฏ๋ก ๋๊ธฐ์ํ๋ก ์ ์ดํ๋ค.(p6, p1-p3)
- ์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค. (Tc2)๊ฐ ๋ผ์ด๋ค๋ฉด์ ๋ฒํผ๊ฐ์ ์ํํ๋ค.
- Tc2๊ฐ ๋ฒํผ๋ฅผ ์๋นํ ์งํ Tc1์ด ์คํ๋๋ค๊ณ ํ์
- ์ ๋ฌํ๊ฒ๋ ๋๊ธฐ์์ ๋ฆฌํดํ๊ธฐ์ ์ ๋ฝ์ ํ๋ํ์ง๋ง ๋ฒํผ๊ฐ ๋น์ด์๋ค.
- Tc1์ด ๋ฒํผ๋ฅผ ์ฝ๋ ํ์๋ฅผ ๋ง์ง ๋ชปํ๋ค.
- ๋ฌธ์ ์ ์์ธ์ ๋จ์ํ๋ค Tc1์ด ์๊ทธ๋์ ๋ฐ๋ ์์ ๊ณผ ์ค๋ ๋๊ฐ ์คํ๋๋ ์์ ์ ์์ฐจ ๋๋ฌธ์ด๋ค.
- ๊นจ์ด๋ค๋ ํ์์ ๋ณธ์ง์ ์ค๋ ๋์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๋๊ฒ์ด๋ค, ๊นจ์ฐ๊ณ ์ค๋๋ ์์ ์ฌ์ด์ ๋ฒํผ๋ ๋ค์ ๋ณ๊ฒฝ๋ ์ ์๋ค.
- ๋๋ฌธ์ ๊นจ์ด๋ ์ค๋ ๋๊ฐ ์ค์ ์คํ๋๋ ์์ ์๋ ์๊ทธ๋์ ๋ฐ์๋ ์์ ์ ์ํ๊ฐ ๊ทธ๋๋ก ์ ์ง๋์ด์๋์ง๋ฅผ ์ฒดํฌํด์ผํ๋ค.
- ์ด๊ฒ์ Mesa semantic์ด๋ผ๊ณ ํ๋ค.
- ๊ฐ์ฅ ๊ฐ๋จํ ํด๊ฒฐ์ฑ ์ if๋ฅผ while๋ฌธ์ผ๋ก ๋ณ๊ฒฝํ๋๊ฒ์ด๋ค
int loops; // must initialize somewhere...
cond_t cond;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
while (count == 1) // p2
Pthread_cond_wait(&cond, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&cond); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
while (count == 0) // c2
Pthread_cond_wait(&cond, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&cond); // c5
Pthread_mutex_unlock(&mutex); // c6
printf("%d\n", tmp);
}
}
-
๋ํ๋์ ๋ฌธ์ ๊ฐ ์๋ค.
-
๋ง์ฝ์ ์์ฐ์๊ฐ ๋ฒํผ๋ฅผ ์ฑ์ฐ๊ณ ,
-
์๋น์๊ฐ ๋น์ฐ๊ณ ,
-
์๋น์๋ฅผ ๋ ๊นจ์ฐ๋ฉด
-
์ธ์์๋ ์ธ๊ฐ์ ์ค๋ ๋๊ฐ ๋ค ์๋ฒ๋ฆด ์ ์๋ค.
-
๋ณ์๋ฅผ ๋๊ฐ์จ์ ํด๊ฒฐํ ์์๊ธฐ๋ํ๋ค.
cond_t empty, fill;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex);
while (count == 1)
Pthread_cond_wait(&empty, &mutex);
put(i);
Pthread_cond_signal(&fill);
Pthread_mutex_unlock(&mutex);
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex);
while (count == 0)
Pthread_cond_wait(&fill, &mutex);
int tmp = get();
Pthread_cond_signal(&empty);
Pthread_mutex_unlock(&mutex);
printf("%d\n", tmp);
}
}
- ์ฌ๊ธฐ์ ์ด๊ฒ๊น์ง๋ง ๊ฐ์ ํด์ฃผ๋ฉด!
#define MAX 100
int buffer[MAX];
int fill = 0;
int use = 0;
int count = 0;
void put(int value) {
buffer[fill] = value;
fill = (fill + 1) % MAX;
count++;
}
int get() {
int tmp = buffer[use];
use = (use + 1) % MAX;
count--;
return tmp;
}
- ๋ค์ค์ค๋ ์ค ์์ฐ์/์๋น์ ํด๋ฒ์ด ์๋ฃ๋์๋ค.
์คํ๋ฝ(Spinlock)๊ณผ ๋ฎคํ ์ค๋ฝ(Mutex lock)์ ์ฃผ์ ์ฐจ์ด์
- ๋์ ๋ฐฉ์:
- ์คํ๋ฝ: ๋ฝ์ ํ๋ํ์ง ๋ชปํ๋ฉด ๊ณ์ํด์ ๋ฝ์ ์ํ๋ฅผ ํ์ธํ๋ฉฐ ๊ธฐ๋ค๋ฆฝ๋๋ค(๋ฐ์ ๋๊ธฐ, busy waiting). CPU ์์์ ๊ณ์ ์๋ชจํ๋ฉด์ ๋ฝ์ด ํ๋ฆด ๋๊น์ง ๋ฐ๋ณต์ ์ผ๋ก ํ์ธํฉ๋๋ค.
- ๋ฎคํ ์ค๋ฝ: ๋ฝ์ ํ๋ํ์ง ๋ชปํ๋ฉด ํ๋ก์ธ์ค/์ค๋ ๋๊ฐ ์ฌ๋ฆฝ(sleep) ์ํ๋ก ์ ํ๋์ด CPU๋ฅผ ์๋ณดํ๊ณ , ๋ฝ์ด ํด์ ๋๋ฉด ๊นจ์ด๋ฉ๋๋ค.
- ์์ ์ฌ์ฉ:
- ์คํ๋ฝ: CPU ์๊ฐ์ ๊ณ์ ์๋ชจํฉ๋๋ค. ๋๊ธฐ ์๊ฐ์ด ์งง์ ๊ฒฝ์ฐ์ ํจ์จ์ ์ ๋๋ค.
- ๋ฎคํ ์ค๋ฝ: ๋๊ธฐ ์ค์๋ CPU๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค. ๋๊ธฐ ์๊ฐ์ด ๊ธธ ๊ฒฝ์ฐ ํจ์จ์ ์ ๋๋ค.
- ์ปจํ
์คํธ ์ค์์นญ:
- ์คํ๋ฝ: ์ปจํ ์คํธ ์ค์์นญ์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
- ๋ฎคํ ์ค๋ฝ: ์ค๋ ๋๊ฐ ์ฌ๋ฆฝ ์ํ๋ก ์ ํ๋ ๋ ์ปจํ ์คํธ ์ค์์นญ์ด ๋ฐ์ํฉ๋๋ค.
- ์ฉ๋:
- ์คํ๋ฝ: ๋ฉํฐํ๋ก์ธ์ ํ๊ฒฝ์์ ๋ฝ ํ๋์ด ๋น ๋ฅด๊ฒ ์ด๋ฃจ์ด์ง ๊ฒ์ผ๋ก ์์๋ ๋ ์ ์ฉํฉ๋๋ค.
- ๋ฎคํ ์ค๋ฝ: ์ผ๋ฐ์ ์ธ ์ํฉ์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ฉฐ, ํนํ ๋๊ธฐ ์๊ฐ์ด ๊ธธ ์ ์๋ ๊ฒฝ์ฐ์ ์ ํฉํฉ๋๋ค.
- ๊ตฌํ ๋ณต์ก์ฑ:
- ์คํ๋ฝ: ์๋์ ์ผ๋ก ๋จ์ํ ๊ตฌํ์ผ๋ก, ์ปค๋ ๋ ๋ฒจ์ ์ง์์ด ์ ๊ฒ ํ์ํฉ๋๋ค.
- ๋ฎคํ ์ค๋ฝ: ์กฐ๊ธ ๋ ๋ณต์กํ ๊ตฌํ์ผ๋ก, ์ปค๋์ ์ค์ผ์ค๋ง ๋ฉ์ปค๋์ฆ๊ณผ ์ฐ๋๋ฉ๋๋ค.
์คํ๋ฝ์ ๋ฝ์ ํ๋ํ๋ ๋ฐ ์งง์ ์๊ฐ์ด ๊ฑธ๋ฆด ๊ฒ์ผ๋ก ์์๋๋ ๊ฒฝ์ฐ๋ ์ค์๊ฐ ์์คํ ์์ ์ปจํ ์คํธ ์ค์์นญ์ ํผํด์ผ ํ ๋ ์ ์ฉํ๋ฉฐ, ๋ฎคํ ์ค๋ฝ์ ๋ฝ ๊ฒฝ์์ด ์ฌํ๊ฑฐ๋ ๋ฝ์ ์ค๋ ๋ณด์ ํด์ผ ํ๋ ์ํฉ์์ ๋ ํจ์จ์
31 ์ธ๋งํฌ์ด
- ์ธ๋งํฌ์ด๋ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์๋ก ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค.
ํต์ฌ์ง๋ฌธ : ์ธ๋งํฌ์ด๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋๊ฐ
32 ๋ณํ์ฑ ๊ด๋ จ ๋ฒ๊ทธ
32.1 ์ค๋ฅ์ ์ข ๋ฅ
- ์ ๋ช ์คํ์์ค๋ฅผ ๋์์ผ๋ก ํ ์ฐ๊ตฌ์์, 105๊ฐ์ ์ค๋ฅ์ค 74๊ฐ๊ฐ ๊ต์ฐฉ์ํ์๋ ๋ฌด๊ดํ ์ค๋ฅ์๋ค.(non-deadlock bug)
32.2 ๋น ๊ต์ฐฉ์ํ ์ค๋ฅ
์์์ฑ ์๋ฐ ์ค๋ฅ
Thread 1::
if (thd->proc_info) {
fputs(thd->proc_info, ...);
}
Thread 2::
thd->proc_info = NULL;
- ์์์ฑ ์๋ฐ์ ๋ํ ์ ์๋ ์ด๋ ๋ค. โ๋ค์์ ๋ฉ๋ชจ๋ฆฌ ์ฐธ์กฐ ์ฐ์ฐ๋ค ๊ฐ์ ์์ด ์์ํ๋ ์ง๋ ฌ์ฑ์ด ๋ณด์ฅ๋์ง ์์๋ค.โ
- ์์์ฑ ์๋ฐ ์ค๋ฅ๋ ํ ํ๋ก์ธ์ค์์ ๊ธฐ๋ํ๋ ์ฐ์ฐ์ด ๋ค๋ฅธ ํ๋ก์ธ์ค์ ๊ฐ์ ์์ด ์์ ํ ์ํ๋์ด์ผ ํ์ง๋ง, ์ค๊ฐ์ ๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ๊ฐ์ ํ์ฌ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ด ๊นจ์ง๋ ๊ฒฝ์ฐ ๋ฐ์ํ๋ค.
- ์๋ฅผ ๋ค์ด, ๋ ๊ฐ์ ์ค๋ ๋๊ฐ ๊ณต์ ๋ณ์ X์ ์ ๊ทผํ๋ค๊ณ ๊ฐ์ ํ ๋, ํ๋์ ์ค๋ ๋๊ฐ X๋ฅผ ์ฝ๊ณ ์์ ํ๋ ๋์ค ๋ค๋ฅธ ์ค๋ ๋๊ฐ X๋ฅผ ๋ณ๊ฒฝํ๋ฉด ์์์น ๋ชปํ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ ์ ์๋ค.
์์ ์๋ฐ์ ์ค๋ฅ
- ๋ณดํต์ ์ปจ๋์ ๋ณ์๊ฐ์๊ฒ๋ค๋ก ํด๊ฒฐ ํ ์ ์๋ค.
- ์์ ์๋ฐ ์ค๋ฅ๋ ํน์ ์ฝ๋ ์คํ ์์๊ฐ ์์๊ณผ ๋ค๋ฅด๊ฒ ์งํ๋์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ๋ฅผ ์๋ฏธํ๋ค.
- ๋ ๊ฐ ์ด์์ ์ค๋ ๋๊ฐ ์คํ๋ ๋, ํน์ ์ด๋ฒคํธ๊ฐ ๋ค๋ฅธ ์ด๋ฒคํธ๋ณด๋ค ๋จผ์ ์คํ๋์ด์ผ ํ๋๋ฐ, ์คํ ์์๊ฐ ๋ณด์ฅ๋์ง ์์ผ๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ค.
- ์๋ฅผ ๋ค์ด, ๋ณ์ Y๊ฐ ์ด๊ธฐํ๋๊ธฐ ์ ์ ๋ค๋ฅธ ์ค๋ ๋์์ ์ด๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ ์๋ค.
32.3 ๊ต์ฐฉ์ํ ์ค๋ฅ
- l1, l2๊ฐ ์์๋ ์ค๋ ๋๊ฐ ์๋ก l2๋ฅผ์ป๊ณ l1์ ๊ธฐ๋ค๋ฆผ, l1์ ์ป๊ณ l2๋ฅผ ๊ธฐ๋ค๋ฆผ ๊ณผ ๊ฐ์ ์ํฉ
- ์ฌ์ค l1, l2๋ฅผ ๋์ผํ ์์๋ก ์ป์ผ๋ฉด ์ด๋ฐ์ผ์ ๋ฐ์์ ์ํจ
- ๊ตฌ์ฑ์์๊ฐ ๋ณต์กํด์ง๋ฉด์ ์ํ ์์กด์ฑ์ด ์๊ธฐ๋ ๊ฒฝ์ฐ์ ์ ๋ฐ์๋จ
๊ฐ์ฅ ํํ๊ฒ๋
Vector v1, v2;
// Thread 1
v1.addAll(v2);
// Thread 2
v1.addAll(v1);
๊ต์ฐฉ ์ํ ๋ฐ์ ์กฐ๊ฑด
- ์ํธ ๋ฐฐ์ (Mutual Exclusion): ์ฐ๋ ๋๊ฐ ์์ ์ด ํ์๋ก ํ๋ ์์์ ๋ํ ๋ ์์ ์ธ ์ ์ด๊ถ์ ์ฃผ์ฅํ๋ค (์, ์ค๋ ๋๊ฐ ๋ฝ์ ํ๋ํจ ).
- ์ ์ ๋ฐ ๋๊ธฐ (Hold-and-wait): ์ฐ๋ ๋๊ฐ ์์ ์๊ฒ ํ ๋น๋ ์์ ( ์ : ์ด๋ฏธ ํ๋ํ ๋ฝ ) ์ ์ ์ ํ ์ฑ๋ก ๋ค๋ฅธ ์์ ( ์ : ํ๋ํ๊ณ ์ ํ๋ ๋ฝ ) ์ ๋๊ธฐํ๋ค.
- ๋น ์ ์ (No preemption): ์์ ( ๋ฝ ) ์ ์ ์ ํ๊ณ ์๋ ์ฐ๋ ๋๋ก๋ถํฐ ์์์ ๊ฐ์ ์ ์ผ๋ก ๋นผ์์ ์ ์๋ค.
- ํํ ๋๊ธฐ(Circular wait): ๊ฐ ์ฐ๋ ๋๋ ๋ค์ ์ฐ๋ ๋๊ฐ ์์ฒญํ ํ๋ ๋๋ ๊ทธ ์ด์์ ์์ ( ๋ฝ ) ์ ๊ฐ๊ณ ์๋ ์ฐ๋ ๋๋ค์ ์ํ ๊ณ ๋ฆฌ๊ฐ ์๋ค.
๊ต์ฐฉ ์ํ์ ์๋ฐฉ
์ํ ๋๊ธฐ
- ๋ฝํ๋์ ํ๋ ์ ์ฒด ์์๋ฅผ ์ ํ๋๊ฒ
- ๋ชจ๋ ์ค๋ ๋๊ฐ lock1 โ lock2 โ lock3 ์์๋ก๋ง ๋ฝ์ ํ๋ํ๋๋ก ๊ท์น์ ์ ํ๋ฉด,
- ํ ์ค๋ ๋๊ฐ lock1์ ์ก์์ ๋ lock2๊ฐ ํ์ํ๋ฉด lock2๋ฅผ ๊ฐ์ง ์ค๋ ๋๋ lock1์ ๊ธฐ๋ค๋ฆด ์ผ์ด ์์ด์ง๋ค.
- ์ด๋ ๊ฒ ํ๋ฉด ํํ ๋๊ธฐ๊ฐ ๋ฐ์ํ์ง ์๋๋ค.
์ ์ ๋ฐ ๋๊ธฐ
- ๋ชจ๋ ๋ฝ์ ๋จ๋ฒ์ ํ๋ํ๋๋ก ํ๋๊ฒ
- lock1๊ณผ lock2๊ฐ ๋ชจ๋ ํ์ํ ๊ฒฝ์ฐ, lock1๋ง ํ๋ํ ํ lock2๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ,
- ์ฒ์๋ถํฐ lock1๊ณผ lock2๋ฅผ ํ๊บผ๋ฒ์ ์์ฒญํ์ฌ ํ๋ํด์ผ ํ๋ค.
- ๋ง์ฝ ๋ ๊ฐ์ ๋ฝ์ ๋์์ ์ป์ ์ ์๋ค๋ฉด, ์์ ๋ฝ์ ์ ์ ํ์ง ์๊ณ ๋ค์ ์๋ํ๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํ ์ ์๋ค.
๋น์ ์
- ์ธํฐํ์ด์ค๋ฅผ ์ ํ์ฉํ๊ธฐ (๋ฝ์ ์ ์ ์ํ ๋ฑ)
- ํน์ ๋ฝ์ด ์ค๋ ์ ์ ๋๊ณ ์์ผ๋ฉด ํ์์์์ ์ค์ ํ์ฌ ์๋์ผ๋ก ํด์ ๋๋๋ก ํ๊ฑฐ๋,
- ์ฐ์ ์์๊ฐ ๋์ ์์ ์ด ์์ฒญ๋์์ ๋ ํ์ฌ ์ ์ ํ ์ค๋ ๋๊ฐ ์์์ ์๋ณดํ๋๋ก ์ค๊ณํ ์ ์๋ค
์ํธ ๋ฐฐ์
- ์ด๋ฐ ์ํฉ ์์ฒด๋ฅผ ์ค์ด๋๋ฒ
- ์ฝ๊ธฐ ์ ์ฉ ์์ ์ ๊ฒฝ์ฐ ๋ฝ์ ์ฌ์ฉํ์ง ์๊ณ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ ๊ทผํ ์ ์๋๋ก ํ๋ค.
- ๊ฐ๋ฅํ๋ฉด ๋ฝ ๋์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ํ์ฉํ๋ ๊ตฌ์กฐ๋ก ๋ณ๊ฒฝํ๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ์ฝ๊ธฐ ์์ ์ ์ํํ ์ ์๋๋ก READ COMMITTED ๊ฐ์ ๊ฒฉ๋ฆฌ ์์ค์ ํ์ฉํ ์ ์๋ค.