**피터슨의 알고리즘**(Peterson's algorithm)은 상호 배제를 위한 병렬 프로그래밍 알고리즘으로서, 공유 메모리를 활용하여 여러 개의 프로세스가 하나의 자원을 함께 사용할 때 문제가 발생하지 않도록 해준다. 수학자 개리 피터슨(Gary Peterson)은 이 알고리즘을 1981년에 로체스터 대학에서 발표하였다. 발표 당시의 알고리즘은 프로세스가 2개인 경우만 적용 가능하고, 이후 3개 이상의 경우에도 적용할 수 있는 방법이 논의되고 있다.

의사 코드
-----

```
 **bool** flag[2] // 불린 배열(Boolean array)
 **int** turn // 정수형 변수
```

```
 flag[0]   = false // false은 임계 구역 사용을 원하지 않음을 뜻함.
 flag[1]   = true
 turn      = 0 // 0 은 0번 프로세스를 가리킴, 1은 1번 프로세스를 가리킴
```

```
 **P0**: flag[0] = true // 임계 구역 사용을 원함
     turn = 1 // 1번 프로세스에게 차례가 감
     **while**( flag[1] **&&** turn == 1 )
     {
          // flag[1] 이 turn[1] 을 가지고 있으므로
          //현재 사용중임
          // 임계 구역이 사용 가능한지 계속 확인
     }// 임계 구역
     ...
    // 임계 구역의 끝
   flag[0] = false
```

```
**P1**: flag[1] = true
    turn = 0
    **while**( flag[0] **&&** turn == 0 )
    {
         // 임계 구역이 사용 가능한지 계속 확인
    }// 임계 구역
    ...
    // 임계 구역의 끝
```

```
    flag[1] = false
```

이 알고리즘은 flag와 turn 변수를 사용한다. flag 값이 true이면 프로세스가 임계 구역에 들어가려고 하는 것을 나타낸다.
이 알고리즘은 임계 구역의 3가지 필수 기준(상호 배제, 진행 조건, 한계 대기)을 충족한다.

두 POSIX 스레드를 활용하여 C언어로 구현한 예
----------------------------

```
/\*
 \* ANSI C89 source, KNF style implementation of Peterson's Algorithm.
 \*
 \* Copyright (c) 2005, Matthew Mondor
 \* Released in the public domain (may be licensed under the GFDL).
 \*
 \* Please fix any bugs as needed, preserving the KNF style and this comment,
 \* unless considered inconvenient in which case you can do whatever you want
 \* with the code.
 \*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

struct pa\_desc {
 volatile int \*f0, \*f1;
 int last;
};

void pa\_init(void);
void pa\_desc\_init(struct pa\_desc \*, int);
void pa\_desc\_lock(struct pa\_desc \*);
void pa\_desc\_unlock(struct pa\_desc \*);

void \*thread0\_main(void \*);
void \*thread1\_main(void \*);
void threadx\_critical(void);

int main(int, char \*\*);

static volatile int pa\_f0, pa\_f1, pa\_last;

/\* 공유 \*/
#define BUCKETS 100
int gi, g[BUCKETS];

/\*
 \* pa 시스템을 초기화 한다.
 \* pa 설명자를 초기화하기 전에, 프로세스에 의해 한번 호출된다.
 \*/
void
pa\_init(void)
{

 pa\_f0 = pa\_f1 = pa\_last = 0;
}

/\*
 \* 스레드가 사용할 pa 설명자를 초기화한다.
 \* 한 스레드는 id 0, 다른 스레드는 id 1을 사용한다.
 \*/
void
pa\_desc\_init(struct pa\_desc \*d, int id)
{

 assert(id == 0 || id == 1);

 if (id == 0) {
 d->f0 = &pa\_f0;
 d->f1 = &pa\_f1;
 d->last = 1;
 } else if (id == 1) {
 d->f0 = &pa\_f1;
 d->f1 = &pa\_f0;
 d->last = 0;
 }
}

void
pa\_desc\_lock(struct pa\_desc \*d)
{

 for (\*d->f0 = 1, pa\_last = d->last;
 \*d->f1 == 1 && pa\_last == d->last; ) ;
}

void
pa\_desc\_unlock(struct pa\_desc \*d)
{

 \*d->f0 = 0;
}

/\*
 \* 첫 번째 동시 스레드의 주요 반복구
 \*/
/\* ARGSUSED \*/
void \*
thread0\_main(void \*args)
{
 struct pa\_desc d;

 pa\_desc\_init(&d, 0);

 for (;;) {
 pa\_desc\_lock(&d);
 threadx\_critical();
 pa\_desc\_unlock(&d);
 }

 /\* 도달하지 않음 \*/
 return NULL;
}

/\*
 \* 두 번째 동시 스레드의 주요 반복구
 \*/
/\* ARGSUSED \*/
void \*
thread1\_main(void \*args)
{
 struct pa\_desc d;
 pa\_desc\_init(&d, 1);

 for (;;) {
 pa\_desc\_lock(&d);
 threadx\_critical();
 pa\_desc\_unlock(&d);
 }

 /\* 도달하지 않음 \*/
 return NULL;
}

/\*
 \* 두 스레드를 잠금(locking)없이 수행할 때
 \* 병행성 처리를 정상적으로 하도록 하는 임계 함수
 \*/
void
threadx\_critical(void)
{
 int i;

 /\* 이중 병행성 처리를 하는 부분 \*/
 for (i = 0; i < BUCKETS; i++)
 g[i] = gi++;
 for (i = 0; i < BUCKETS; i++)
 (void) printf("g[%d] = %d\n", i, g[i]);
}

/\*
 \* 이 테스트 프로그램은 피터스 알고리즘을 사용하여, 잠금(locking) 기능 없이도
 \* 이중 병행 작업을 수행할 수 있다. 즉, 별도의 안전장치없이 동시에 수행할 경우
 \* 발생하는 공유 메모리 문제를 방지할 수 있다.
 \*/
/\* ARGSUSED \*/
int
main(int argc, char \*\*argv)
{
 pthread\_t tid1, tid2;
 pthread\_attr\_t tattr;

 gi = 0;
 pa\_init();

 pthread\_attr\_init(&tattr);
 pthread\_attr\_setdetachstate(&tattr, 0);

 /\* 주: 실제 응용 프로그램은 오류 검사를 수행해야 함 \*/
 pthread\_create(&tid1, &tattr, thread0\_main, NULL);
 pthread\_create(&tid2, &tattr, thread1\_main, NULL);

 pthread\_join(tid1, NULL);
 pthread\_join(tid2, NULL);
 /\* 도달하지 않음 \*/

 return EXIT\_SUCCESS;
}

```