8 min read

OSTEP 29 Locked Data Structures

Table of Contents

ํ”ํ•˜๊ฒŒ ์‚ฌ์šฉ๋˜๋Š” ์ž๋ฃŒ ๊ตฌ์กฐ์—์„œ ๋ฝ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์ž. ์ž๋ฃŒ ๊ตฌ์กฐ์— ๋ฝ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๋ฉด ๊ทธ ๊ตฌ์กฐ๋Š” thread safeํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŠน์ • ์ž๋ฃŒ ๊ตฌ์กฐ๊ฐ€ ์ฃผ์–ด์กŒ์„ ๋•Œ, ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ฝ์„ ์ถ”๊ฐ€ํ•ด์•ผ ๊ทธ ์ž๋ฃŒ ๊ตฌ์กฐ๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ? ๋” ๋‚˜์•„๊ฐ€ ์ž๋ฃŒ ๊ตฌ์กฐ์— ๋ฝ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ทธ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๋™์‹œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•˜๋ฉด (๋ณ‘ํ–‰์„ฑ) ๊ณ ์„ฑ๋Šฅ์„ ์–ป๊ธฐ ์œ„ํ•ด ๋ฌด์—‡์„ ํ•ด์•ผ ํ• ๊นŒ?

1. ๋ณ‘ํ–‰ ์นด์šดํ„ฐ

์นด์šดํ„ฐ๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ์ž๋ฃŒ ๊ตฌ์กฐ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๋ณ‘ํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ์นด์šดํ„ฐ๋ฅผ ๋จผ์ € ๋ณด์ž.

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 safeํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?

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

์ด ์นด์šดํ„ฐ๋Š” ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ๊ธฐ๋ณธ์ ์ธ ๋ณ‘ํ–‰ ์ž๋ฃŒ ๊ตฌ์กฐ์˜ ๋ณดํŽธ์ ์ธ ๋””์ž์ธ ํŒจํ„ด์„ ๋”ฐ๋ฅธ ๊ฒƒ์ด๋‹ค. ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๋ฃจํ‹ด์„ ํ˜ธ์ถœํ•  ๋•Œ ๋ฝ์„ ์ถ”๊ฐ€ํ•˜์˜€๊ณ , ๊ทธ ํ˜ธ์ถœ๋ฌธ์ด ๋ฆฌํ„ด๋  ๋•Œ ๋ฝ์ด ํ•ด์ œ๋˜๋„๋ก ํ•˜์˜€๋‹ค.

์ด ๋ฐฉ์‹์€ Monitor๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งŒ๋“  ์ž๋ฃŒ ๊ตฌ์กฐ์™€ ์œ ์‚ฌํ•˜๋‹ค. ๋ชจ๋‹ˆํ„ฐ ๊ธฐ๋ฒ•์€ ๊ฐ์ฒด์— ๋Œ€ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๋ฆฌํ„ดํ•  ๋•Œ ์ž๋™์ ์œผ๋กœ ๋ฝ์„ ํš๋“ํ•˜๊ณ  ํ•ด์ œํ•œ๋‹ค.

์ด์ œ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜๋Š” ๋ณ‘ํ–‰ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜์—ˆ์ง€๋งŒ, ์„ฑ๋Šฅ์ด ๋ฌธ์ œ๋‹ค. ์ด๋ฒˆ ์žฅ์—์„œ๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ค.

๊ฐ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํŠน์ • ํšŸ์ˆ˜๋งŒํผ ๊ณต์œ  ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฒค์น˜๋งˆํฌ๋ฅผ ์‹คํ–‰ํ•˜์˜€๋‹ค.

OSTEP 29 Locked Data Structures-1694400264405.jpeg

1๊ฐœ์—์„œ 4๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นด์šดํ„ฐ๋ฅผ ๋ฐฑ๋งŒ ๋ฒˆ ์ฆ๊ฐ€์‹œ์ผฐ์„ ๋•Œ ์ด ๊ฑธ๋ฆฐ ์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ์ด๋‹ค. precise๋ผ๊ณ  ํ‘œ์‹œ๋œ ์„ ์—์„œ ๋™๊ธฐํ™”๋œ ์นด์šดํ„ฐ์˜ ํ™•์žฅ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด์ƒ์ ์œผ๋กœ๋Š” ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ CPU์—์„œ ์ž‘์—…์„ ๋๋‚ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์„œ์—์„œ ์‹คํ–‰๋˜๋Š” ์“ฐ๋ ˆ๋“œ๋“ค๋„ ๋น ๋ฅด๊ฒŒ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ด๋‹ค(์™„๋ฒฝํ•œ ํ™•์žฅ์„ฑ: perfect scaling).

ํ™•์žฅ์„ฑ ์žˆ๋Š” ์นด์šดํŒ…

ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์นด์šดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด Linux์˜ ๋ช‡๋ช‡ ์ž‘์—…์€ ๋ฉ€ํ‹ฐ์ฝ”์–ด ๊ธฐ๊ธฐ์—์„œ ์‹ฌ๊ฐํ•œ ํ™•์žฅ์„ฑ ๋ฌธ์ œ๋ฅผ ๊ฒช์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

์—ฌ๋Ÿฌ ๊ธฐ๋ฒ• ์ค‘ ํ•˜๋‚˜์ธ ์—‰์„ฑํ•œ ์นด์šดํ„ฐ(sloppy counter) ๋ฅผ ์†Œ๊ฐœํ•œ๋‹ค.

์—‰์„ฑํ•œ ์นด์šดํ„ฐ๋Š” ํ•˜๋‚˜์˜ ๋…ผ๋ฆฌ์  ์นด์šดํ„ฐ๋กœ ํ‘œํ˜„๋˜๋Š”๋ฐ, CPU ์ฝ”์–ด๋งˆ๋‹ค ์กด์žฌํ•˜๋Š” ํ•˜๋‚˜์˜ ๋ฌผ๋ฆฌ์ ์ธ ์ง€์—ญ ์นด์šดํ„ฐ์™€ ํ•˜๋‚˜์˜ ์ „์—ญ ์นด์šดํ„ฐ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. ์–ด๋–ค ๊ธฐ๊ธฐ๊ฐ€ ๋„ค ๊ฐœ์˜ CPU๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ๊ทธ ์‹œ์Šคํ…œ์€ ๋„ค ๊ฐœ์˜ ์ง€์—ญ ์นด์šดํ„ฐ์™€ ํ•˜๋‚˜์˜ ์ „์—ญ ์นด์šดํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ์ด ์นด์šดํ„ฐ๋“ค ์™ธ์—๋„, ์ง€์—ญ ์นด์šดํ„ฐ๋ฅผ ์œ„ํ•œ ๋ฝ๋“ค๊ณผ ์ „์—ญ ์นด์šดํ„ฐ๋ฅผ ์œ„ํ•œ ๋ฝ์ด ์กด์žฌํ•œ๋‹ค.

๊ธฐ๋ณธ ๊ฐœ๋…์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

์“ฐ๋ ˆ๋“œ๋Š” ์ง€์—ญ ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€์‹œํ‚จ๋‹ค. ์ด ์ง€์—ญ ์นด์šดํ„ฐ๋Š” ์ง€์—ญ ๋ฝ์— ์˜ํ•ด ๋ณดํ˜ธ๋œ๋‹ค. ๊ฐ CPU๋Š” ์ €๋งˆ๋‹ค ์ง€์—ญ ์นด์šดํ„ฐ๋ฅผ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— CPU๋“ค์— ๋ถ„์‚ฐ๋˜์–ด ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋“ค์€ ์ง€์—ญ ์นด์šดํ„ฐ๋ฅผ ๊ฒฝ์Ÿ ์—†์ด ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์นด์šดํ„ฐ ๊ฐฑ์‹ ์€ ํ™•์žฅ์„ฑ์ด ์žˆ๋‹ค.

์“ฐ๋ ˆ๋“œ๊ฐ€ ์นด์šดํ„ฐ์˜ ๊ฐ’์„ ์ฝ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ „์—ญ ์นด์šดํ„ฐ๋ฅผ ์ตœ์‹ ์œผ๋กœ ๊ฐฑ์‹ ํ•ด์•ผ ํ•œ๋‹ค. ์ตœ์‹  ๊ฐ’์œผ๋กœ ๊ฐฑ์‹ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ง€์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์ „์—ญ ์นด์šดํ„ฐ๋กœ ์ „๋‹ฌ๋˜๋Š”๋ฐ, ์ด๋•Œ ์ „์—ญ ๋ฝ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง€์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์„ ์ „์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์— ๋”ํ•˜๊ณ , ๊ทธ ์ง€์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์€ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

์ง€์—ญ์—์„œ ์ „์—ญ์œผ๋กœ ๊ฐ’์„ ์ „๋‹ฌํ•˜๋Š” ๋นˆ๋„๋Š” ์ •ํ•ด ๋†“์€ SS ๊ฐ’์— ์˜ํ•ด์„œ ๊ฒฐ์ •๋œ๋‹ค. SS์˜ ๊ฐ’์ด ์ž‘์„ ์ˆ˜๋ก ํ™•์žฅ์„ฑ ์—†๋Š” ์นด์šดํ„ฐ์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ณ , ์ปค์งˆ์ˆ˜๋ก ์ „์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์€ ์‹ค์ œ ๊ฐ’๊ณผ ์ฐจ์ด๊ฐ€ ์žˆ๊ฒŒ ๋œ๋‹ค.

OSTEP 29 Locked Data Structures-1694400794159.jpeg

์ด ์˜ˆ์ œ์—์„œ๋Š” ํ•œ๊ณ„์น˜๋ฅผ 5๋กœ ์„ค์ •ํ–ˆ๊ณ , 4๊ฐœ์˜ CPU์— ๊ฐ๊ฐ์˜ ์ง€์—ญ ์นด์šดํ„ฐ L1L_1 โ€ฆ L4L_4 ๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋“ค์ด ์žˆ๋‹ค. ์ „์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’ GG๋„ ๋‚˜ํƒ€๋‚ด์—ˆ๋‹ค. ์ง€์—ญ ์นด์šดํ„ฐ๊ฐ€ ํ•œ๊ณ„์น˜ SS์— ๋„๋‹ฌํ•˜๋ฉด ๊ทธ ๊ฐ’์€ ์ „์—ญ ์นด์šดํ„ฐ์— ๋ฐ˜์˜๋˜๊ณ  ์ง€์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์€ ์ดˆ๊ธฐํ™”๋œ๋‹ค.

OSTEP 29 Locked Data Structures-1694400927480.jpeg

SS๊ฐ’์ด ๋‚ฎ๋‹ค๋ฉด ์„ฑ๋Šฅ์ด ๋‚ฎ์€ ๋Œ€์‹  ์ „์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์ด ๋งค์šฐ ์ •ํ™•ํ•ด์ง„๋‹ค. SS๊ฐ’์ด ๋†’๋‹ค๋ฉด ์„ฑ๋Šฅ์€ ํƒ์›”ํ•˜์ง€๋งŒ ์ „์—ญ ์นด์šดํ„ฐ์˜ ๊ฐ’์€ CPU์˜ ๊ฐœ์ˆ˜์™€ SS์˜ ๊ณฑ๋งŒํผ ๋’ค์ณ์ง€๊ฒŒ ๋œ๋‹ค.

typedef struct __counter_t {
	int global;
	pthread_mutex_t glock;
	int local[NUMCPUS];
	pthread_mutex_t llock[NUMCPUS]; 
	int threshold;
} counter_t;

void init(counter_t *c, int threshold) {
	cโˆ’>threshold = threshold;
	
	cโˆ’>global = 0;
	pthread_mutex_init(&cโˆ’>glock, NULL);
	
	int i;
	for (i = 0; i < NUMCPUS; i++) {
		cโˆ’>local[i] = 0;
		pthread_mutex_init(&cโˆ’>llock[i], NULL);
	}
}

void update(counter_t *c, int threadID, int amt) {
	pthread_mutex_lock(&cโˆ’>llock[threadID]);
	cโˆ’>local[threadID] += amt; 
	if (cโˆ’>local[threadID] >= cโˆ’>threshold) {
		pthread_mutex_lock(&cโˆ’>glock);
		cโˆ’>global += cโˆ’>local[threadID];
		pthread_mutex_unlock(&cโˆ’>glock);
		cโˆ’>local[threadID] = 0;
	}
	pthread_mutex_unlock(&cโˆ’>llock[threadID]);
}

int get(counter_t *c) {
	pthread_mutex_lock(&cโˆ’>glock);
	int val = cโˆ’>global;
	pthread_mutex_unlock(&cโˆ’>glock);
	return val;
}

2. ๋ณ‘ํ–‰ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ

์ด์ œ ์กฐ๊ธˆ ๋” ๋ณต์žกํ•œ ๊ตฌ์กฐ์ธ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋‹ค๋ค„๋ณด์ž. ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ‘ํ–‰ ์‚ฝ์ž… ์—ฐ์‚ฐ๋งŒ ์‚ดํŽด๋ณด๋„๋ก ํ•˜์ž.

typedef struct __node_t {
	int key;
	struct __node_t *next;
} node_t;

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;
	}
	newโˆ’>key = key;
	newโˆ’>next = Lโˆ’>head;
	Lโˆ’>head = new;
	pthread_mutex_unlock(&Lโˆ’>lock);
	return 0;
}

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;
		}
		curr = currโˆ’>next;
	}
	pthread_mutex_unlock(&Lโˆ’>lock);
	return โˆ’1;
}

์‚ฝ์ธ ์—ฐ์‚ฐ์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ๋ฝ์„ ํš๋“ํ•˜๊ณ  ๋ฆฌํ„ด ์ง์ „์— ํ•ด์ œํ•œ๋‹ค. ๋งค์šฐ ๋“œ๋ฌธ ๊ฒฝ์šฐ์ง€๋งŒ malloc()์ด ์‹คํŒจํ•  ๊ฒฝ์šฐ์— ๋ฏธ๋ฌ˜ํ•œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ์‹คํŒจ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์ „์— ๋ฝ์„ ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค.

์‚ฝ์ž… ์—ฐ์‚ฐ์ด ๋ณ‘ํ–‰ํ•˜์—ฌ ์ง„ํ–‰๋˜๋Š” ์ƒํ™ฉ์—์„œ ์‹คํŒจ๋ฅผ ํ•˜๋”๋ผ๋„ ๋ฝ ํ•ด์ œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ์‚ฝ์ž…๊ณผ ๊ฒ€์ƒ‰์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ์‚ฝ์ž… ์ฝ”๋“œ์—์„œ ์ž„๊ณ„ ์˜์—ญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„๋งŒ ๋ฝ์œผ๋กœ ๊ฐ์‹ธ๋„๋ก ์ฝ”๋“œ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๊ฒ€์ƒ‰ ์ฝ”๋“œ์˜ ์ข…๋ฃŒ๋Š” ๊ฒ€์ƒ‰๊ณผ ์‚ฝ์ž… ๋ชจ๋‘ ๋™์ผํ•œ ์ฝ”๋“œ ํŒจ์Šค๋ฅผ ์‚ฌ์šฉํ† ๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์ด ๋™์ž‘ํ•˜๋Š” ์ด์œ ๋Š” ์ฝ”๋“œ ์ผ๋ถ€๋Š” ์‚ฌ์‹ค ๋ฝ์ด ํ•„์š” ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

malloc() ์ž์ฒด๊ฐ€ thread safeํ•˜๋‹ค๋ฉด, ์“ฐ๋ ˆ๋“œ๋Š” ์–ธ์ œ๋“ ์ง€ ๊ฒฝ์Ÿ ์กฐ๊ฑด๊ณผ ๋‹ค๋ฅธ ๋ณ‘ํ–‰์„ฑ ๊ด€๋ จ ๋ฒ„๊ทธ๋ฅผ ๊ฑฑ์ •ํ•˜์ง€ ์•Š์œผ๋ฉด์„œ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ณต์œ  ๋ฆฌ์ŠคํŠธ ๊ฐฑ์‹  ๋•Œ์—๋งŒ ๋ฝ์„ ํš๋“ํ•˜๋ฉด ๋œ๋‹ค.

ํ™•์žฅ์„ฑ ์žˆ๋Š” ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ

๋ณ‘ํ–‰์ด ๊ฐ€๋Šฅํ•œ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ–๊ฒŒ ๋˜์—ˆ์ง€๋งŒ, ํ™•์žฅ์„ฑ์ด ์ข‹์ง€ ์•Š๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์ž.

๋ณ‘ํ–‰์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋กœ hand-over-hand locking(๋˜๋Š” lock coupling) ์ด๋ผ๋Š” ๊ธฐ๋ฒ•์„ ๊ฐœ๋ฐœํ–ˆ๋‹ค.

๊ฐœ๋…์€ ๋‹จ์ˆœํ•˜๋‹ค. ์ „์ฒด ๋ฆฌ์ŠคํŠธ์— ํ•˜๋‚˜์˜ ๋ฝ์ด ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ฐœ๋ณ„ ๋…ธ๋“œ๋งˆ๋‹ค ๋ฝ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•  ๋•Œ ๋‹ค์Œ ๋…ธ๋“œ์˜ ๋ฝ์„ ๋จผ์ € ํš๋“ํ•˜๊ณ  ์ง€๊ธˆ ๋…ธ๋“œ์˜ ๋ฝ์„ ํ•ด์ œํ•˜๋„๋ก ํ•œ๋‹ค.

void List_Init(list_t *L) {
	Lโˆ’>head = NULL;
	pthread_mutex_init(&Lโˆ’>lock, NULL);
}

void List_Insert(list_t *L, int key) {
	// ๋™๊ธฐํ™”๋ฅผ ํ•  ํ•„์š” ์—†์Œ
	node_t *new = malloc(sizeof(node_t));
	
	if (new == NULL) {
		perror(โ€œmalloc โ€);
		return;
	}
	newโˆ’>key = key;

	// ์ž„๊ณ„ ์˜์—ญ๋งŒ ๋ฝ์œผ๋กœ ๋ณดํ˜ธ
	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; // ์„ฑ๊ณต ํ˜น์€ ์‹คํŒจ
}

๋ฆฌ์ŠคํŠธ ์—ฐ์‚ฐ์— ๋ณ‘ํ–‰์„ฑ์ด ๋†’์•„์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ดœ์ฐฎ์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ํ•˜์ง€๋งŒ, ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•  ๋•Œ ๊ฐ ๋…ธ๋“œ์— ๋ฝ์„ ํš๋“ํ•˜๊ณ  ํ•ด์ œํ•˜๋Š” ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋งค์šฐ ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์†๋„ ๊ฐœ์„ ์„ ๊ธฐ๋Œ€ํ•˜๊ธฐ ์‰ฝ์ง€ ์•Š๋‹ค.

๋ฝ ํš๋“/ํ•ด์ œ์™€ ๊ฐ™์ด ๋ถ€ํ•˜๊ฐ€ ํฐ ์—ฐ์‚ฐ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ–ˆ๋‹ค๋ฉด, ๋ณ‘ํ–‰์„ฑ ์ž์ฒด๊ฐ€ ์ข‹์•„์กŒ๋‹ค๋Š” ๊ฒƒ์€ ํฐ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค. ์˜คํžˆ๋ ค, ๋ถ€ํ•˜๊ฐ€ ํฐ ๋ฃจํ‹ด์€ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด ๋” ์ข‹๋‹ค. ๋ฝ์„ ๋งŽ์ด ์ถ”๊ฐ€ํ•˜๊ณ  ๋ณต์žก๋„๊ฐ€ ์ฆ๊ฐ€ํ•˜๋ฉด ํฐ ๋‹จ์ ์ด ๋œ๋‹ค. ์–ด๋А ๊ฒƒ์ด ๋” ์ข‹์€์ง€ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋”ฑ ํ•œ ๊ฐ€์ง€์ด๋‹ค. ๊ฐ„๋‹จํ•˜์ง€๋งŒ ๋ณ‘ํ–‰์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๊ฒƒ๊ณผ ๋ณต์žกํ•˜์ง€๋งŒ ๋ณ‘ํ–‰์„ฑ์ด ๋†’์€ ๋‘ ๊ฒฝ์šฐ๋ฅผ ๋‹ค ๊ตฌํ˜„ํ•˜๊ณ  ์„ฑ๋Šฅ์„ ์ธก์ •ํ•ด ๋ณด์•„์•ผ ํ•œ๋‹ค. ์„ฑ๋Šฅ์„ ์†์ผ ์ˆ˜๋Š” ์—†์ง€ ์•Š๋Š”๊ฐ€. ๊ฒฐ๊ณผ๋Š” โ€œ์ข‹๋‹คโ€, โ€œ๋‚˜์˜๋‹คโ€ ๋‘˜ ์ค‘์— ํ•˜๋‚˜์ผ ํ…Œ๋‹ˆ๊นŒ ๋ง์ด๋‹ค.

3. ๋ณ‘ํ–‰ ํ

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 headLock;
	pthread_mutex_t tailLock;
} 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โˆ’>headLock, NULL);
	pthread_mutex_init(&qโˆ’>tailLock, 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โˆ’>tailLock);
	qโˆ’>tailโˆ’>next = tmp;
	qโˆ’>tail = tmp;
	pthread_mutex_unlock(&qโˆ’>tailLock);
}

int Queue_Dequeue(queue_t *q, int *value) {
	pthread_mutex_lock(&qโˆ’>headLock);
	node_t *tmp = qโˆ’>head;
	node_t *newHead = tmpโˆ’>next;
	if (newHead == NULL) {
		pthread_mutex_unlock(&qโˆ’>headLock);
		return โˆ’1;
	}
	*value = newHeadโˆ’>value;
	qโˆ’>head = newHead;
	pthread_mutex_unlock(&qโˆ’>headLock);
	free(tmp);
	return 0;
}

4. ๋ณ‘ํ–‰ ํ•ด์‹œ ํ…Œ์ด๋ธ”

์ „์ฒด ์ž๋ฃŒ ๊ตฌ์กฐ์— ํ•˜๋‚˜์˜ ๋ฝ์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ•ด์‹œ ๋ฒ„์ผ“ (๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์Œ) ๋งˆ๋‹ค ๋ฝ์„ ์‚ฌ์šฉํ•˜์—ฌ์„œ ์„ฑ๋Šฅ์ด ์šฐ์ˆ˜ํ•˜๋‹ค.

#define BUCKETS ()

typedef struct __hash_t {
	list_t lists[BUCKETS];
} hash_t;
 
void Hash_Init(hash_t *H) {
	int i;
	for (i = ; i < BUCKETS; i++) {
		List_Init(&Hโˆ’>lists[i]);
	}
}

int Hash_Insert(hash_t *H, int key) {
	int bucket = key % BUCKETS;
	return List_Insert(&Hโˆ’>lists[bucket], key);
}

int Hash_Lookup(hash_t *H, int key) {
	int bucket = key % BUCKETS;
	return List_Lookup(&Hโˆ’>lists[bucket], key);
}

OSTEP 29 Locked Data Structures-1694421703747.jpeg

5. ์š”์•ฝ

๋ฝ ํš๋“๊ณผ ํ•ด์ œ ์‹œ ์ฝ”๋“œ์˜ ํ๋ฆ„์— ๋งค์šฐ ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์—ฌ์•ผ ํ•œ๋‹ค. ๋ณ‘ํ–‰์„ฑ ๊ฐœ์„ ์ด ๋ฐ˜๋“œ์‹œ ์„ฑ๋Šฅ ๊ฐœ์„ ์œผ๋กœ ์ด์–ด์ง€๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์„ฑ๋Šฅ ๊ฐœ์„ ์€ ์„ฑ๋Šฅ์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๊ฒฐ์ฑ…์„ ๊ฐ•๊ตฌํ•ด์•ผ ํ•œ๋‹ค.

๋ฝ์„ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋™๊ธฐํ™” ๊ธฐ๋ฒ•๋“ค๋„ ์ถ”ํ›„์— ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ค.