7 min read

OSTEP 26 Concurrency and Threads

Table of Contents

이번 μž₯μ—μ„œλŠ” ν”„λ‘œμ„ΈμŠ€λ₯Ό μœ„ν•œ μƒˆλ‘œμš΄ κ°œλ…μΈ μ“°λ ˆλ“œ (Thread) λ₯Ό μ†Œκ°œν•œλ‹€. ν”„λ‘œκ·Έλž¨μ—μ„œ ν•œ μˆœκ°„μ— ν•˜λ‚˜μ˜ λͺ…λ Ήμ–΄λ§Œμ„ μ‹€ν–‰ν•˜λŠ” (단일 Program Counter) 고전적인 κ΄€μ μ—μ„œ λ²—μ–΄λ‚˜, λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž¨μ€ ν•˜λ‚˜ μ΄μƒμ˜ μ‹€ν–‰ 지점 (λ…λ¦½μ μœΌλ‘œ λΆˆλŸ¬λ“€μ—¬μ§€κ³  싀행될 수 μžˆλŠ” μ—¬λŸ¬ 개의 Program Counter κ°’) 을 κ°€μ§€κ³  μžˆλ‹€.

각 μ“°λ ˆλ“œλŠ” ν”„λ‘œμ„ΈμŠ€μ™€ μœ μ‚¬ν•˜μ§€λ§Œ μ“°λ ˆλ“œλΌλ¦¬ μ£Όμ†Œ 곡간을 κ³΅μœ ν•˜κΈ° λ•Œλ¬Έμ— λ™μΌν•œ 값에 μ ‘κ·Όν•  수 μžˆλ‹€.

ν•˜λ‚˜μ˜ μ“°λ ˆλ“œμ˜ μƒνƒœλŠ” ν”„λ‘œμ„ΈμŠ€μ™€ μœ μ‚¬ν•˜κ²Œ μ–΄λ””μ„œ λͺ…령어듀을 λΆˆλŸ¬μ˜¬μ§€ μΆ”μ ν•˜λŠ” PC와 연산을 μœ„ν•œ λ ˆμ§€μŠ€ν„°λ₯Ό κ°€μ§€κ³  μžˆλ‹€. 두 개의 μ“°λ ˆλ“œκ°€ ν•˜λ‚˜μ˜ ν”„λ‘œμ„Έμ„œμ—μ„œ μ‹€ν–‰ 쀑이라면 두 번째 μ“°λ ˆλ“œλŠ” λ¬Έλ§₯ κ΅ν™˜μ„ 톡해 첫 번째 μ“°λ ˆλ“œμ™€ κ΅μ²΄λ˜μ–΄μ•Ό ν•œλ‹€. 첫 번째 μ“°λ ˆλ“œκ°€ μ‚¬μš©ν•˜λ˜ λ ˆμ§€μŠ€ν„°λ₯Ό μ €μž₯ν•˜κ³ , 두 번째 μ“°λ ˆλ“œκ°€ μ‚¬μš©ν•˜λ˜ λ ˆμ§€μŠ€ν„°μ˜ λ‚΄μš©μœΌλ‘œ λŒλ €λ†“λŠ”λ‹€λŠ” μ μ—μ„œ ν”„λ‘œμ„ΈμŠ€μ˜ λ¬Έλ§₯ κ΅ν™˜κ³Ό μœ μ‚¬ν•˜λ‹€.

ν”„λ‘œμ„ΈμŠ€κ°€ ν”„λ‘œμ„ΈμŠ€ μ œμ–΄ λΈ”λŸ­ (PCB) 에 μ €μž₯ν•˜λ“―, ν”„λ‘œμ„ΈμŠ€μ˜ μ“°λ ˆλ“œλ“€μ˜ μƒνƒœλ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•΄ μ“°λ ˆλ“œ μ œμ–΄ λΈ”λŸ­ (TCB) κ°€ ν•„μš”ν•˜λ‹€. κ°€μž₯ 큰 차이점은 μ“°λ ˆλ“œ κ°„ λ¬Έλ§₯ κ΅ν™˜μ—μ„œλŠ” μ£Όμ†Œ 곡간을 κ·ΈλŒ€λ‘œ μ‚¬μš©ν•œλ‹€λŠ” 점이닀.

μ“°λ ˆλ“œμ™€ ν”„λ‘œμ„ΈμŠ€μ˜ 또 λ‹€λ₯Έ μ°¨μ΄λŠ” μŠ€νƒμ— μžˆλ‹€. λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ˜ κ²½μš°μ—λŠ”, 각 μ“°λ ˆλ“œκ°€ λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰λ˜λ©°, μ£Όμ†Œ κ³΅κ°„μ—λŠ” μ“°λ ˆλ“œλ§ˆλ‹€ μŠ€νƒμ΄ ν• λ‹Ήλ˜μ–΄ μžˆλ‹€.

OSTEP 26 Concurrency and Threads-1694363175880.jpeg

였λ₯Έμͺ½ μ£Όμ†Œ κ³΅κ°„μ—λŠ” 두 개의 μŠ€νƒμ΄ μ‘΄μž¬ν•œλ‹€. μŠ€νƒμ—μ„œ ν• λ‹Ήλ˜λŠ” λ³€μˆ˜λ“€μ΄λ‚˜ λ§€κ°œλ³€μˆ˜, 리턴값 등은 ν•΄λ‹Ή μ“°λ ˆλ“œμ˜ μŠ€νƒμΈ μ“°λ ˆλ“œ-둜컬 μ €μž₯μ†Œ(Thread-local storage) 에 μ €μž₯λœλ‹€.

μ“°λ ˆλ“œ-둜컬 μ €μž₯μ†Œλ‘œ 인해 μ •κ΅ν•œ μ£Όμ†Œ κ³΅κ°„μ˜ λ°°μΉ˜κ°€ λ¬΄λ„ˆμ Έλ²„λ Έλ‹€. μŠ€νƒ 사이에 빈 곡간이 생겨버렸닀. μŠ€νƒμ˜ 크기가 μ•„μ£Ό 크지 μ•Šμ•„λ„ 되기 λ•Œλ¬Έμ— λŒ€λΆ€λΆ„μ˜ κ²½μš°λŠ” λ¬Έμ œκ°€ λ˜μ§€ μ•ŠλŠ”λ‹€. μž¬κ·€ ν˜ΈμΆœμ„ 많이 ν•˜λ©΄ λ¬Έμ œκ°€ 생길 수 μžˆλ‹€.

예제: μ“°λ ˆλ“œ 생성

β€œA”, β€œB”λ₯Ό 좜λ ₯ν•˜λŠ” 독립적인 두 개의 μ“°λ ˆλ“œλ₯Ό λ§Œλ“€μ–΄λ³΄μž.

#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;
}

mythread() ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•  두 개의 μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•œλ‹€. μŠ€μΌ€μ€„λŸ¬κ°€ μ–΄λ–»κ²Œ ν•˜λŠλƒμ— λ‹¬λ €μžˆκΈ΄ ν•˜μ§€λ§Œ, μ“°λ ˆλ“œκ°€ μƒμ„±λ˜λ©΄ μ¦‰μ‹œ 싀행될 μˆ˜λ„ 있고, μ€€λΉ„ μƒνƒœμ—μ„œ 싀행은 λ˜μ§€ μ•Šμ„ μˆ˜λ„ μžˆλ‹€.

두 개의 μ“°λ ˆλ“œλ₯Ό μƒμ„±ν•œ 후에 메인 μ“°λ ˆλ“œλŠ” pthread_join()을 ν˜ΈμΆœν•˜μ—¬ νŠΉμ • μ“°λ ˆλ“œμ˜ λ™μž‘μ˜ μ’…λ£Œλ₯Ό λŒ€κΈ°ν•œλ‹€.

OSTEP 26 Concurrency and Threads-1694363842948.jpeg OSTEP 26 Concurrency and Threads-1694363849892.jpeg

μ΄λ ‡κ²Œ μ‹€ν–‰ μˆœμ„œλŠ” μ—¬λŸ¬ κ°€μ§€λ‘œ λ‚˜μ˜¬ 수 μžˆλ‹€. μ“°λ ˆλ“œ 1이 μ“°λ ˆλ“œ 2보닀 λ¨Όμ € μƒμ„±λœ κ²½μš°λΌλ„, μŠ€μΌ€μ€„λŸ¬κ°€ μ“°λ ˆλ“œ 2λ₯Ό λ¨Όμ € μ‹€ν–‰ν•˜λ©΄ β€œB”가 β€œA”보닀 λ¨Όμ € 좜λ ₯될 μˆ˜λ„ μžˆλ‹€.

μ“°λ ˆλ“œμ˜ 생성이 ν•¨μˆ˜μ˜ 호좜과 μœ μ‚¬ν•˜κ²Œ 보인닀. ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œλŠ” ν•¨μˆ˜ μ‹€ν–‰ 후에 호좜자 (caller) μ—κ²Œ λ¦¬ν„΄ν•˜λŠ” 반면, μ“°λ ˆλ“œμ˜ μƒμ„±μ—μ„œλŠ” μ‹€ν–‰ν•  λͺ…령어듀을 κ°–κ³  μžˆλŠ” μƒˆλ‘œμš΄ μ“°λ ˆλ“œκ°€ μƒμ„±λ˜κ³ , μƒμ„±λœ μ“°λ ˆλ“œλŠ” callerμ™€λŠ” λ³„κ°œλ‘œ μ‹€ν–‰λœλ‹€. μ“°λ ˆλ“œ 생성 ν•¨μˆ˜κ°€ λ¦¬ν„΄λ˜κΈ° 전에 μ“°λ ˆλ“œκ°€ 싀행될 μˆ˜λ„ 있고, λ¦¬ν„΄λœ 이후에 μ“°λ ˆλ“œκ°€ 싀행될 μˆ˜λ„ μžˆλ‹€.

μ΄λ ‡κ²Œ μ“°λ ˆλ“œλŠ” μ–Έμ œ μ‹€ν–‰λ˜λŠ”μ§€ μ•ŒκΈ° μ–΄λ ΅λ‹€.

2. 훨씬 더 μ–΄λ €μš΄ 이유: λ°μ΄ν„°μ˜ 곡유

μ „μ—­ 곡유 λ³€μˆ˜λ₯Ό κ°±μ‹ ν•˜λŠ” 두 개의 μ“°λ ˆλ“œμ— λŒ€ν•œ 예제λ₯Ό μ‚΄νŽ΄λ³΄μž.

#include <stdio.h>
#include <pthread.h>
#include "ommon.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;
}

λ‹€μŒκ³Ό 같은 κ²°κ³Όλ₯Ό κΈ°λŒ€ν•  것이닀.

1 prompt> gcc βˆ’o main main.c βˆ’Wall βˆ’pthread
2 prompt> ./main
3 main: begin (counter = 0)
4 A: begin
5 B: begin
6 A: done
7 B: done
8 main: done with both (counter = 20000000)

ν•˜μ§€λ§Œ 이 μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ κΈ°λŒ€ν•œ λŒ€λ‘œ κ²°κ³Όκ°€ 좜λ ₯λ˜μ§€ μ•ŠλŠ”λ‹€.

1 prompt> ./main
2 main: begin (counter = 0)
3 A: begin
4 B: begin
5 A: done
6 B: done
7 main: done with both (counter = 19345221)

λ‹€μ‹œ ν•œ 번 싀행해보면, 또 λ‹€λ₯Έ κ²°κ³Όκ°€ λ‚˜μ˜¨λ‹€.

1 prompt> ./main
2 main: begin (counter = 0)
3 A: begin
4 B: begin
5 A: done
6 B: done
7 main: done with both (counter = 19221041)

μ™œ 이런 일이 μΌμ–΄λ‚˜λŠ” 걸까?

3. μ œμ–΄ μ—†λŠ” μŠ€μΌ€μ€„λ§

μ™œ 이런 일이 μΌμ–΄λ‚˜λŠ”μ§€ μ•ŒκΈ° μœ„ν•΄, μ»΄νŒŒμΌλŸ¬κ°€ μƒμ„±ν•œ μ½”λ“œμ˜ μ‹€ν–‰ μˆœμ„œλ₯Ό 이해할 ν•„μš”κ°€ μžˆλ‹€. x86μ—μ„œ counterλ₯Ό μ¦κ°€ν•˜λŠ” μ½”λ“œμ˜ μˆœμ„œλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

mov 0x8049a1c, %eax
add $0x1, %eax
mov %eax, 0x8049a1c

counter λ³€μˆ˜μ˜ μ£Όμ†Œκ°€ 0x8049a1c이라고 ν•˜μž. mov λͺ…λ Ήμ–΄κ°€ λͺ…μ‹œν•œ μ£Όμ†Œμ˜ 값을 읽어듀인 ν›„, eax λ ˆμ§€μŠ€ν„°μ— λ„£λŠ”λ‹€. 그리고 1을 (0x1) eax λ ˆμ§€μŠ€ν„°μ˜ 값에 λ”ν•˜λŠ” 연산을 ν•œ ν›„, eax λ ˆμ§€μŠ€ν„°μ— μ €μž₯된 κ·Έ 값을 λ©”λͺ¨λ¦¬μ˜ μ›λž˜ μ£Όμ†Œμ— λ‹€μ‹œ μ €μž₯ν•œλ‹€.

무슨 λ¬Έμ œκ°€ 생길지 μ˜ˆμƒν•  수 μžˆλ‹€.

1번 μ“°λ ˆλ“œκ°€ counterλ₯Ό 1 μ¦κ°€μ‹œν‚€λ €κ³  ν•œλ‹€. counter에 50이 μ €μž₯λ˜μ–΄ μžˆμ—ˆκΈ° λ•Œλ¬Έμ—, eax λ ˆμ§€μŠ€ν„°μ— λ„£λŠ”λ‹€. eax λ ˆμ§€μŠ€ν„°μ— 1을 λ”ν•΄μ„œ eax λ ˆμ§€μŠ€ν„°μ˜ 값이 51이 λœλ‹€.

이 λ•Œ 타이머 μΈν„°λŸ½νŠΈκ°€ λ°œμƒν•˜μ—¬ μš΄μ˜μ²΄μ œκ°€ 1번 μ“°λ ˆλ“œμ˜ PC와 λ ˆμ§€μŠ€ν„° λ“±μ˜ μƒνƒœλ₯Ό μ“°λ ˆλ“œμ˜ TCB에 μ €μž₯ν•œλ‹€.

그리고 2번 μ“°λ ˆλ“œκ°€ μ„ νƒλ˜κ³  counterλ₯Ό μ¦κ°€μ‹œν‚€λŠ” μ½”λ“œ μ˜μ—­μ— μ§„μž…ν•œλ‹€. 아직 counterμ—λŠ” 50이 μ €μž₯λ˜μ–΄ 있기 λ•Œλ¬Έμ— λ˜‘κ°™μ΄ 50을 읽고, eax λ ˆμ§€μŠ€ν„°μ— μ €μž₯ν•˜κ³ , 1 μ¦κ°€μ‹œν‚€κ³ , κ·Έ 값을 counter의 μ£Όμ†Œ 0x8049a1c에 μ €μž₯ν•œλ‹€. μ“°λ ˆλ“œλŠ” κ°œλ³„μ μœΌλ‘œ μ“°λ ˆλ“œ μ „μš© λ ˆμ§€μŠ€ν„°λ₯Ό κ°€μ§€κ³  μžˆλ‹€. μ‚¬μš© μ€‘μ΄λ˜ λ ˆμ§€μŠ€ν„°λ“€μ„ μ €μž₯ν•˜κ³  λ³΅κ΅¬ν•˜λŠ” κΈ°λŠ₯ 덕뢄에 이 λ ˆμ§€μŠ€ν„°λ“€μ€ κ°€μƒν™”λ˜μ–΄ 각 μ“°λ ˆλ“œκ°€ κ°œλ³„μ μœΌλ‘œ μ‚¬μš©ν•  수 있게 λœλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ λ¬Έλ§₯ κ΅ν™˜μ΄ ν•œλ²ˆ 더 μΌμ–΄λ‚˜μ„œ 1번 μ“°λ ˆλ“œκ°€ μ‹€ν–‰λœλ‹€. counter의 μ£Όμ†Œ 0x8049a1c에 eax λ ˆμ§€μŠ€ν„°μ˜ κ°’ 51을 μ €μž₯ν•œλ‹€.

OSTEP 26 Concurrency and Threads-1694368241373.jpeg

이 μ˜ˆμ‹œμ²˜λŸΌ λͺ…λ Ήμ–΄μ˜ μ‹€ν–‰ μˆœμ„œμ— 따라 κ²°κ³Όκ°€ λ‹¬λΌμ§€λŠ” 상황을 경쟁 쑰건 (race condition) 이라고 ν•œλ‹€. 경쟁 쑰건에 μ²˜ν•œ 경우 μ‹€ν–‰ν•  λ•Œλ§ˆλ‹€ λ‹€λ₯Έ κ²°κ³Όλ₯Ό μ–»λŠ”λ‹€. 즉, **비결정적(indeterminate)**이닀.

λ©€ν‹° μ“°λ ˆλ“œκ°€ 같은 μ½”λ“œλ₯Ό μ‹€ν–‰ν•  λ•Œ 경쟁 쑰건이 λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ΄λŸ¬ν•œ μ½”λ“œ 뢀뢄을 μž„κ³„ μ˜μ—­ (critical section) 이라고 λΆ€λ₯Έλ‹€. 곡유 λ³€μˆ˜λ₯Ό μ ‘κ·Όν•˜κ³ , ν•˜λ‚˜ μ΄μƒμ˜ μ“°λ ˆλ“œμ—μ„œ λ™μ‹œμ— μ‹€ν–‰λ˜λ©΄ μ•ˆ λ˜λŠ” μ½”λ“œλ₯Ό μž„κ³„ μ˜μ—­μ΄λΌ λΆ€λ₯Έλ‹€.

이 λ•Œ ν•„μš”ν•œ 것은 μƒν˜Έ 배제 (mutual exclusion) 이닀. 이 속성은 ν•˜λ‚˜μ˜ μ“°λ ˆλ“œκ°€ μž„κ³„ μ˜μ—­ λ‚΄μ˜ μ½”λ“œλ₯Ό μ‹€ν–‰ 쀑일 λ•ŒλŠ” λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ μž„κ³„ μ˜μ—­μ— μ§„μž…ν•˜λŠ” 것을 막아 μ‹€ν–‰ν•  수 없도둝 보μž₯ν•΄ μ€€λ‹€.

4. μ›μžμ„±μ— λŒ€ν•œ λ°”λžŒ

κ°•λ ₯ν•œ λͺ…λ Ήμ–΄ ν•œ 개둜 μ˜λ„ν•œ λ™μž‘μ„ μˆ˜ν–‰ν•˜μ—¬ μΈν„°λŸ½νŠΈ λ°œμƒ κ°€λŠ₯성을 μ›μ²œ 차단할 수 μžˆμ„κΉŒ?

memoryβˆ’add 0x8049a1c, $0x1

λ©”λͺ¨λ¦¬ μƒμ˜ μœ„μΉ˜μ— μ–΄λ–€ 값을 λ”ν•˜λŠ”, μ•„μ£Ό κ°•λ ₯ν•œ λͺ…λ Ήμ–΄λ‹€. 이 λͺ…λ Ήμ–΄κ°€ μ›μžμ μœΌλ‘œ μ‹€ν–‰λ˜λŠ” 것을 보μž₯ν•œλ‹€κ³  ν•˜μž.

β€œμ›μžμ (atomic)β€œμ΄λΌλŠ” μš©μ–΄λŠ” μ—¬λŸ¬ 개의 μž‘μ—…μ΄λ‚˜ λͺ…령이 μžˆμ„ λ•Œ κ·Έ 쀑 ν•˜λ‚˜μ˜ μž‘μ—… λ˜λŠ” λͺ…령이 쀑간에 μΈν„°λŸ½νŠΈλ˜κ±°λ‚˜ μ€‘λ‹¨λ˜μ§€ μ•Šκ³  ν•œ λ²ˆμ— μ™„μ „νžˆ μ‹€ν–‰λ˜λŠ” 것을 μ˜λ―Έν•©λ‹ˆλ‹€. 즉, μ›μžμ μΈ 연산은 β€œλΆ„ν•  λΆˆκ°€λŠ₯β€ν•˜λ‹€κ³  λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 특히 병렬 μ²˜λ¦¬λ‚˜ λ©€ν‹° μŠ€λ ˆλ”© ν™˜κ²½μ—μ„œ μ€‘μš”ν•œ κ°œλ…μž…λ‹ˆλ‹€. μ—¬λŸ¬ μŠ€λ ˆλ“œ λ˜λŠ” ν”„λ‘œμ„ΈμŠ€κ°€ λ™μ‹œμ— 같은 λ©”λͺ¨λ¦¬ μœ„μΉ˜μ— μ ‘κ·Όν•˜λŠ” 경우, μ›μžμ  연산은 λ°μ΄ν„°μ˜ 일관성을 μœ μ§€ν•˜κΈ° μœ„ν•΄ μ€‘μš”ν•©λ‹ˆλ‹€.

μ–΄λ–»κ²Œ ν•˜λ©΄

mov 0x8049a1c, %eax
add $0x1, %eax
mov %eax, 0x8049a1c

이녀석을 μ›μžμ μœΌλ‘œ μ‹€ν–‰ν•  수 μžˆμ„κΉŒ? ν•˜λ‚˜μ˜ λͺ…λ Ήμ–΄λ‘œ ν•΄κ²°λœλ‹€λ©΄ μ’‹κ² μ§€λ§Œ μΌλ°˜μ μœΌλ‘œλŠ” λΆˆκ°€λŠ₯ν•˜λ‹€. B-tree의 값을 μ›μžμ μœΌλ‘œ κ°±μ‹ ν•˜λŠ” μ–΄μ…ˆλΈ”λ¦¬ λͺ…λ Ήμ–΄κ°™μ€κ²Œ μžˆμ„κΉŒ? 그런 건 μ—†λ‹€.

ν•˜λ“œμ›¨μ–΄ 동기화 λͺ…령어와 운영체제의 지원을 톡해 ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ§Œ μž„κ³„ μ˜μ—­μ—μ„œ μ‹€ν–‰ν•˜λ„λ‘ κ΅¬μ„±λœ, μ œλŒ€λ‘œ 잘 μž‘λ™ν•˜λŠ” λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•  수 μžˆλ‹€.

5. 또 λ‹€λ₯Έ 문제: μƒλŒ€ 기닀리기

μ§€κΈˆκΉŒμ§€λŠ” 병행성 문제λ₯Ό 곡유 λ³€μˆ˜ 접근에 κ΄€λ ¨λœ μ“°λ ˆλ“œ κ°„μ˜ μƒν˜Έ μž‘μš© 문제둜 μ •μ˜ν•˜μ˜€μ§€λ§Œ, μ‹€μ œλ‘œλŠ” ν•˜λ‚˜μ˜ μ“°λ ˆλ“œκ°€ λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ λ™μž‘μ„ μ „λΆ€ 끝낼 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•΄μ•Ό ν•˜λŠ” 상황도 μΌμ–΄λ‚œλ‹€. ν”„λ‘œμ„ΈμŠ€κ°€ λ””μŠ€ν¬ I/Oλ₯Ό μš”μ²­ν•˜κ³  응닡이 올 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦¬λŠ” 경우 등이 μžˆλ‹€.

6. 정리: μ™œ μš΄μ˜μ²΄μ œμ—μ„œ?

μ™œ 이런걸 μš΄μ˜μ²΄μ œμ—μ„œ λ‹€λ£¨λŠ”κ±ΈκΉŒ? 이것이 β€œμ—­μ‚¬β€ 이기 λ•Œλ¬Έμ΄λ‹€. μš΄μ˜μ²΄μ œλŠ” 졜초의 병행 ν”„λ‘œκ·Έλž¨μ΄μ—ˆκ³  운영체제 λ‚΄μ—μ„œ μ‚¬μš©μ„ λͺ©μ μœΌλ‘œ λ‹€μ–‘ν•œ 기법듀이 κ°œλ°œλ˜μ—ˆλ‹€. λ‚˜μ€‘μ—λŠ” λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž¨μ΄ λ“±μž₯ν•˜λ©΄μ„œ μ‘μš© ν”„λ‘œκ·Έλž˜λ¨Έλ“€λ„ 이 문제λ₯Ό κ³ λ―Όν•˜κ²Œ λ˜μ—ˆλ‹€.

μ‹œλ„ λ•Œλ„ 없이 λ°œμƒν•˜λŠ” μΈν„°λŸ½νŠΈκ°€ μ•žμ„œ μ–ΈκΈ‰ν•œ λͺ¨λ“  λ¬Έμ œλ“€μ˜ 원인이닀. νŽ˜μ΄μ§€ ν…Œμ΄λΈ”, ν”„λ‘œμ„ΈμŠ€ 리슀트, 파일 μ‹œμŠ€ν…œ ꡬ쑰 그리고 λŒ€λΆ€λΆ„μ˜ 컀널 자료 ꡬ쑰듀이 μ˜¬λ°”λ₯΄κ²Œ λ™μž‘ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ μ ˆν•œ 동기화 ν•¨μˆ˜λ“€μ„ μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.