25 ๋ณ‘ํ–‰์„ฑ์— ๊ด€ํ•œ ๋Œ€ํ™”

์—ฌ๋Ÿฌ์‚ฌ๋žŒ์ด ๋™์‹œ์— ๋ณต์ˆญ์•„๋ฅผ ์ง‘์„ ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์„๋•Œ๋Š” ๋นจ๋ž์–ด์š”, ๋ฐ˜๋ฉด์— ์ œ ๋ฐฉ๋ฒ•์€ ํ•œ๋ฒˆ์— ํ•œ๋ช…์”ฉ ์ง‘๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ™•ํ•˜๊ฒ ์ง€๋งŒ ๊ฝค ๋Š๋ฆฌ๊ฒ ๊ตฐ์š”.

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

๋™์‹œ์„ฑ์„ ์šด์˜์ฒด์ œ์—์„œ ๋‹ค๋ค„์•ผ ํ•  ๋ช‡ ๊ฐ€์ง€ ์ด์œ ๊ฐ€ ์žˆ์ง€. ์šด์˜์ฒด์ œ๋Š” ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜์™€ ๊ฐ™์€ ๊ธฐ๋ณธ ๋™์ ์œผ๋กœ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์„ ์ง€์›ํ•ด์•ผ ํ•œ๋‹ค๋„ค. ๋‘˜์งธ๋กœ ์šด์˜์ฒด์ œ๋Š” ๊ทธ ์ž์ฒด๋กœ ์ตœ์ดˆ์˜ ๋™์‹œ ํ”„๋กœ๊ทธ๋žจ์ด๊ธฐ ๋•Œ๋ฌธ์ด์•ผ

26 ๋ณ‘ํ–‰์„ฑ: ๊ฐœ์š”

  • ํ”„๋กœ๊ทธ๋žจ์—์„œ ํ•œ ์ˆœ๊ฐ„์— ํ•˜๋‚˜์˜ ๋ช…๋ น์–ด๋งŒ์„ ์‹คํ–‰ํ•˜๋Š” (๋‹จ์ผ PC๊ฐ’) ๊ณ ์ „์ ์ธ ๊ด€์ ์—์„œ ๋ฒ—์–ด๋‚˜ ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์€ ํ•˜๋‚˜ ์ด์ƒ์˜ ์‹คํ–‰ ์ง€์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค(๋…๋ฆฝ์ ์œผ๋กœ ๋ถˆ๋Ÿฌ ๋“ค์—ฌ์ง€๊ณ  ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ PC๊ฐ’).
  • ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ดํ•ดํ•˜๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์€ ๊ฐ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ”„๋กœ์„ธ์Šค์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค๋ฉด ์“ฐ๋ ˆ๋“œ๋“ค์€ ์ฃผ์†Œ๊ณต๊ฐ„์„ ๊ณต์œ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์˜ ์ƒํƒœ๋Š” ํ”„๋กœ์„ธ์Šค์˜ ์ƒํƒœ์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜๋‹ค. ์Šค๋ ˆ๋“œ๋Š” ์–ด๋””์„œ ๋ช…๋ น์–ด๋ฅผ ๋ถˆ๋Ÿฌ๋“ค์ผ์ง€ ์ถ”์ ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ ์นด์šดํ„ฐ์™€ ์—ฐ์‚ฐ์„ ์œ„ํ•œ ๋ ˆ์ง€์Šคํ„ฐ๋“ค์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.
  • ๋งŒ์•ฝ ๋‘๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์„œ์—์„œ ์‹คํ–‰์ค‘์ด๋ผ๋ฉด ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ context switch์„ ํ†ตํ•ด์„œ ์‹คํ–‰์ค‘์ด ์Šค๋ ˆ๋“œ์™€ ๊ต์ฒด๋˜์–ด์•ผ ํ•œ๋‹ค.
  • ์Šค๋ ˆ๋“œ์˜ ๋ฌธ๋งฅ๊ตํ™˜์€ t1์ด ์‚ฌ์šฉํ•˜๋˜ ๋ ˆ์ง€์Šคํ„ฐ๋“ค์„ ์ €์žฅํ•˜๊ณ  t2๊ฐ€ ์‚ฌ์šฉํ•˜๋˜ ๋ ˆ์ง€์Šคํ„ฐ์˜ ๋‚ด์šฉ์œผ๋กœ ๋ณต์›ํ•œ๋‹ค๋Š” ์ ์—์„œ ํ”„๋กœ์„ธ์Šค์˜ ๋ฌธ๋งฅ ๊ตํ™˜๊ณผ ์œ ์‚ฌํ•˜๋‹ค.
  • ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋ฌธ๋งฅ ๊ตํ™˜์„ ํ•ผ ๋•Œ์— ํ”„๋กœ์„ธ์Šค์˜ ์ƒํƒœ๋ฅผ ํ”„๋กœ์„ธ์Šค ์ œ์–ด ๋ธ”๋Ÿญ์— ์ €์žฅํ•˜๋“ฏ์ด ์Šค๋ ˆ๋“œ๋Š” ์Šค๋ ˆ๋“œ ์ œ์–ด ๋ธ”๋Ÿญ์ด ํ•„์š”ํ•˜๋‹ค.
  • ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ค‘ ํ•˜๋‚˜๋Š” ํ”„๋กœ์„ธ์Šค์˜ ๊ฒฝ์šฐ์˜ค ๋‹ฌ๋ฆฌ ์Šค๋ ˆ๋“œ๊ฐ„์˜ ๋ฌธ๋งฅ ๊ตํ™˜์—์„œ๋Š” ์ฃผ์†Œ๊ณต๊ฐ„์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ์Šค๋ ˆ๋“œ์™€ ํ”„๋กœ์„ธ์Šค์˜ ๋˜ ๋‹ค๋Š” ์ฐจ์ด๋Š” ์Šคํƒ์— ์žˆ๋‹ค. ๊ณ ์ „์  ํ”„๋กœ์„ธ์Šค ์ฃผ์†Œ๊ณต๊ฐ„๊ณผ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๋ชจ๋ธ์—์„œ๋Š” ์Šคํƒ์ด ํ•˜๋‚˜๋งŒ ์กด์žฌํ•œ๋‹ค.(์ฃผ๋กœ ์ฃผ์†Œ ๊ณต๊ฐ„์˜ ํ•˜๋ถ€์—)
  • ๋ฐ˜๋ฉด์— ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ”„๋กœ์„ธ์Šค์˜ ๊ฒฝ์šฐ์—๋Š” ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ ์ฃผ์†Œ๊ณต๊ฐ„์—๋Š” ํ•˜๋‚˜์˜ ์Šคํƒ์ด ์•„๋‹ˆ๋ผ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ์Šคํƒ์ด ํ• ๋‹น๋˜์–ด ์žˆ๋‹ค. Image

26.1 ์™œ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

  • ์šฐ๋ฆฌ๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐฐ์šธ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ ์ „์— ์™œ ์‚ฌ์šฉํ•˜๋Š”์ง€์˜ ํšจ์šฉ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณผ๊ฒƒ์ด๋‹ค.
  • ์ฃผ์š”ํ•˜๊ฒŒ๋Š” ๋‘๊ฐ€์ง€ ์ด์œ ๊ฐ€ ์žˆ๋‹ค.
    • ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ (parallelism) :
      • ์˜ˆ๋ฅผ ๋“ค์–ด ๋‘๊ฐœ์˜ ํฐ ๋ฐฐ์—ด์„ ๋”ํ•˜๊ฑฐ๋‚˜, ๋ฐฐ์—ด์˜ ๊ฐ ์›์†Œ ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋งค์šฐ ํฐ ๋ฐฐ์—ด์„ ๋Œ€์ƒ์œผ๋กœ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋”ฐ๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.
      • ๋‹จ์ผํ”„๋กœ์„ธ์Šค๋Š” ๊ฐ„๋‹จํ•˜๋‹ค - ๊ฐ ์ž‘์—…์„ ํ•˜๋‚˜์”ฉ ์ˆ˜ํ–‰ ํ›„ ์™„๋ฃŒ
      • ๊ทธ๋Ÿฌ๋‚˜ ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค์‹œ์Šคํ…œ์—์„œ๋Š” ๊ฐ ํ”„๋กœ์„ธ์„œ๊ฐ€ ์ž‘์—…์˜ ์ผ๋ถ€๋ถ„์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•จ์œผ๋กœ์จ ์‹คํ–‰์†๋„๋ฅผ ๋†’์ผ์ˆ˜ ์žˆ๋‹ค.
      • ํ‘œ์ค€ ๋‹จ์ผ ์Šค๋ ˆ๋“œ ํ”„๋กœ๊ทธ๋žจ์„ ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์„œ์ƒ์—์„œ ๊ฐ™์€ ์ž‘์—…์„ ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์ž‘์—…์„ ๋ณ‘๋ คํ™”๋ผ๊ณ  ํ•œ๋‹ค.
    • ๋‘๋ฒˆ์งธ๋Š” ์•ฝ๊ฐ„ ๋ฏธ๋ฌ˜ํ•œ๋ฐ, ๋Š๋ฆฐ I/O๋กœ ์ธํ•ด ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰์ด ๋ฉˆ์ถ”์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•œ๋‹ค.
      • ํ”„๋กœ๊ทธ๋žจ์ค‘ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋Œ€๊ธฐํ•˜๋Š”๋™์•ˆ ์Šค์ผ€์ค„๋Ÿฌ๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๊ณ  ์ด ์Šค๋ ˆ๋“œ๋Š” ์ค€๋น„ ์ƒํƒœ์ด๋ฉฐ ์œ ์šฉํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

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

Image

Image

  • ํ•จ์ˆ˜ ํ˜ธ์ถœ์ฒ˜๋Ÿผ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ๋„ ํ•œ๋‹ค.
  • ํ•จ์ˆ˜ํ˜ธ์ถœ์—์„œ๋Š” ํ•จ์ˆ˜์‹คํ–‰ํ›„์— ํ˜ธ์ถœ์ž์—๊ฒŒ ๋ฆฌํ„ดํ•˜๋Š” ๋ฐ˜๋ฉด์— ์Šค๋ ˆ๋“œ์˜ ์ƒ์„ฑ์—์„œ๋Š” ์‹คํ–‰ํ•  ๋ช…๋ น์–ด๋“ค์„ ๊ฐ–๊ณ ์žˆ๋Š” ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ƒ์„ฑ๋œ ์Šค๋ ˆ๋“œ๋Š” ํ˜ธ์ถœ์ž์™€๋Š” ๋ณ„๊ฐœ๋กœ ์‹คํ–‰๋œ๋‹ค.
  • ์Šค๋ ˆ๋“œ ์ƒ์„ฑํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ด๋˜๊ธฐ ์ „์— ์Šค๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ ๋  ์ˆ˜ ๋„ ์žˆ๊ณ , ๊ทธ๋ณด๋‹ค ์ดํ›„์— ์‹คํ–‰ ๋  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‹ค์Œ์— ์‹คํ–‰๋  ์Šค๋ ˆ๋“œ๋Š” ์Šค์ผ€์ค„๋Ÿฌ์— ์˜ํ•ด ๊ฒฐ์ •๋œ๋‹ค.
  • ์ด ์˜ˆ์ œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ ์Šค๋ ˆ๋“œ๋Š” ์ผ์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.

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 ๋ฌธ์ œ์˜ ํ•ต์‹ฌ: ์ œ์–ด ์—†๋Š” ์Šค์ผ€์ค„๋ง

Image

  • ์š”์•ฝํ•˜๋ฉด 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์—์„œ๋Š” ๋งค์šฐ ๋Š๋ฆฌ๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.)

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์ดˆ๊ฐ€ ๊ฑธ๋ฆฌ๊ฑฐ๋‚˜

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

  • ๊ทธ๋ž˜์„œ ๊ทผ์‚ฌ ์นด์šดํ„ฐ (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) ;
  • ๊ณผ์ •์„ ๋ช…ํ™•ํžˆ ๊ธฐ์–ตํ•ด์•ผ ํ•œ๋‹ค.
    1. ์Šฌ๋ฆฝ์—์„œ ๊นจ์–ด๋‚œ ํ”„๋กœ์„ธ์Šค๋Š” ๋ฆฌํ„ดํ•˜๊ธฐ ์ „์— ๋ฝ์„ ์žฌํš๋“ํ•ด์•ผํ•œ๋‹ค.
    2. ์‹œ๊ทธ๋„์„ ๋ฐ›์•„์„œ ๋Œ€๊ธฐ์ƒํƒœ์—์„œ ๊นจ์–ด๋‚ฌ๋”๋ผ๋„ ๋ฝํš๋“์— ์‹คํŒจํ•˜๋ฉด ๋‹ค์‹œ ์Šฌ๋ฆฝํ•œ๋‹ค.

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)์˜ ์ฃผ์š” ์ฐจ์ด์ 

  1. ๋™์ž‘ ๋ฐฉ์‹:
    • ์Šคํ•€๋ฝ: ๋ฝ์„ ํš๋“ํ•˜์ง€ ๋ชปํ•˜๋ฉด ๊ณ„์†ํ•ด์„œ ๋ฝ์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜๋ฉฐ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค(๋ฐ”์œ ๋Œ€๊ธฐ, busy waiting). CPU ์ž์›์„ ๊ณ„์† ์†Œ๋ชจํ•˜๋ฉด์„œ ๋ฝ์ด ํ’€๋ฆด ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต์ ์œผ๋กœ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฎคํ…์Šค๋ฝ: ๋ฝ์„ ํš๋“ํ•˜์ง€ ๋ชปํ•˜๋ฉด ํ”„๋กœ์„ธ์Šค/์Šค๋ ˆ๋“œ๊ฐ€ ์Šฌ๋ฆฝ(sleep) ์ƒํƒœ๋กœ ์ „ํ™˜๋˜์–ด CPU๋ฅผ ์–‘๋ณดํ•˜๊ณ , ๋ฝ์ด ํ•ด์ œ๋˜๋ฉด ๊นจ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  2. ์ž์› ์‚ฌ์šฉ:
    • ์Šคํ•€๋ฝ: CPU ์‹œ๊ฐ„์„ ๊ณ„์† ์†Œ๋ชจํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ์งง์€ ๊ฒฝ์šฐ์— ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
    • ๋ฎคํ…์Šค๋ฝ: ๋Œ€๊ธฐ ์ค‘์—๋Š” CPU๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๊ธธ ๊ฒฝ์šฐ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.
  3. ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ:
    • ์Šคํ•€๋ฝ: ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ๋ฎคํ…์Šค๋ฝ: ์Šค๋ ˆ๋“œ๊ฐ€ ์Šฌ๋ฆฝ ์ƒํƒœ๋กœ ์ „ํ™˜๋  ๋•Œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  4. ์šฉ๋„:
    • ์Šคํ•€๋ฝ: ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์„œ ํ™˜๊ฒฝ์—์„œ ๋ฝ ํš๋“์ด ๋น ๋ฅด๊ฒŒ ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฎคํ…์Šค๋ฝ: ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋ฉฐ, ํŠนํžˆ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด ๊ธธ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  5. ๊ตฌํ˜„ ๋ณต์žก์„ฑ:
    • ์Šคํ•€๋ฝ: ์ƒ๋Œ€์ ์œผ๋กœ ๋‹จ์ˆœํ•œ ๊ตฌํ˜„์œผ๋กœ, ์ปค๋„ ๋ ˆ๋ฒจ์˜ ์ง€์›์ด ์ ๊ฒŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฎคํ…์Šค๋ฝ: ์กฐ๊ธˆ ๋” ๋ณต์žกํ•œ ๊ตฌํ˜„์œผ๋กœ, ์ปค๋„์˜ ์Šค์ผ€์ค„๋ง ๋ฉ”์ปค๋‹ˆ์ฆ˜๊ณผ ์—ฐ๋™๋ฉ๋‹ˆ๋‹ค.

์Šคํ•€๋ฝ์€ ๋ฝ์„ ํš๋“ํ•˜๋Š” ๋ฐ ์งง์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋˜๋Š” ๊ฒฝ์šฐ๋‚˜ ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ์—์„œ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์„ ํ”ผํ•ด์•ผ ํ•  ๋•Œ ์œ ์šฉํ•˜๋ฉฐ, ๋ฎคํ…์Šค๋ฝ์€ ๋ฝ ๊ฒฝ์Ÿ์ด ์‹ฌํ•˜๊ฑฐ๋‚˜ ๋ฝ์„ ์˜ค๋ž˜ ๋ณด์œ ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๋” ํšจ์œจ์ 

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 ๊ฐ™์€ ๊ฒฉ๋ฆฌ ์ˆ˜์ค€์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.