프로그램이 받아야 하는 인자들 (모든 시간은 밀리세컨드 단위)
1. number_of_philosophers
: 철학자의 수 == 포크의 수
2. time_to_die
: 마지막 식사 또는 프로그램 시작 후 이 시간 동안 먹지 못하면 사망
3. time_to_eat
: 철학자가 식사하는 데 걸리는 시간 == 포크 두 개를 가지고 있는 시간
4. time_to_sleep
: 철학자가 자는 데 걸리는 시간
5. number_of_times_each_philosopher_must_eat
: 선택. 모든 철학자가 이 수만큼 식사를 마치면 프로그램 종료. 정의되지 않는 경우 철학자의 사망 시에만 프로그램 종료
1
부터 number_of_philosophers
까지 번호를 부여받음number_of_philosophers
번 철학자 옆에 앉음N
번 철학자는 N-1
번 철학자와 N+1
번 철학자 사이에 앉음)컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램
메모리에 올라와 실행되고 있는 프로그램의 인스턴스
프로세스 내에서 실행되는 여러 흐름의 단위
CPU에서 여러 프로세스를 돌아가면서 처리하는 것
동작 중인 프로세스가 대기를 하면서 해당 프로세스의 상태(Context)를 보관하고, 다음 우선 순위의 프로세스가 동작하면서 이전에 보관했던 프로세스의 상태를 복구하는 작업
프로세스에서 여러 스레드를 돌아가면서 처리하는 것
여러 스레드가 같은 데이터를 공유할 때 발생
Mutual Exclusion, 상호배제
여러 스레드가 공유하는 자원을 보호하기 위해 사용되는 도구 (데이터 경쟁 방지)
memset
printf
malloc
free
write
usleep()
주어진 시간 동안 스레드의 실행을 지연시킴
#include <unistd.h>
int usleep(useconds_t microseconds);
gettimeofday()
그리니치 표준시와 타임존을 구조체에 세팅해주는 함수
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
timeval
과 timezone
은 sys/time.h에 아래와 같이 정의되어 있음NULL
을 전달하면 NULL
이 아닌 포인터만 세팅됨NULL
이면 아무것도 하지 않음0
, 실패 시 -1
리턴struct timeval {
time_t tv_sec; /* seconds since Jan. 1, 1970 */
suseconds_t tv_usec; /* and microseconds */
};
struct timezone {
int tz_minuteswest; /* of Greenwich */
int tz_dsttime; /* type of dst correction to apply */
};
tv_sec
: 초 단위tv_usec
: 마이크로세컨드 단위 (초로 표현할 수 없는 상세한 정보)(tv_sec * 1000) + (tv_usec / 1000)
: 밀리세컨드로 현재 시각 계산아래
pthread_
함수들은 모두 pthread.h에 정의됨
pthread_create()
새 스레드 생성
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
pthread_t *thread
: 생성한 스레드를 저장할 포인터pthread_attr_t *attr
: 스레드에 지정할 속성. NULL
이면 기본 속성 사용void *(*start_routine)(void *)
start_routine
에 전달된 함수를 실행하며 생성됨pthread_exit()
의 인자로 전달되어 스레드를 종료void *arg
: start_routine
함수에 전달할 인자0
, 실패 시 오류 번호 리턴❗️ 여기서 생성된 스레드의 메모리는 다른 스레드에서 pthread_join
이나 pthread_detach
를 통해 회수되어야 함 (그렇지 않으면 누수 발생!)
pthread_detach()
스레드가 종료될 때 메모리를 회수하도록 지정하는 함수
(타겟 스레드를 메인 스레드에서 분리시킴으로써 타겟 스레드가 종료되는 즉시 자원을 반환하는 동작을 보증)
👉 스레드 생성 후 호출
int pthread_detach(pthread_t thread);
0
, 실패 시 오류 번호 리턴pthread_join()
타겟 스레드가 종료될 때까지 현재 스레드의 실행을 지연시키는 함수
(타겟 스레드가 종료될 때 메모리를 회수하는 함수)
👉 타겟 스레드를 종료하고 싶을 때 호출
int pthread_join(pthread_t thread, void **value_ptr);
void **value_ptr
: NULL
이 아닌 값이 전달된 경우, 종료된 스레드에 의해 pthread_exit()
에 전달된 값(스레드의 리턴값)이 여기에 저장됨0
, 실패 시 오류 번호 리턴pthread_mutex_init()
뮤텍스 생성
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
pthread_mutex_t *mutex
: 생성된 뮤텍스를 저장할 포인터const pthread_mutexattr_t *attr
: 뮤텍스에 지정할 속성. NULL
이면 기본 속성 사용0
, 실패 시 오류 번호 리턴pthread_mutex_destroy()
뮤텍스에 할당된 메모리 반환
int pthread_mutex_destroy(pthread_mutex_t *mutex);
0
, 실패 시 오류 번호 리턴pthread_mutex_lock()
뮤텍스 잠금
int pthread_mutex_lock(pthread_mutex_t *mutex);
0
, 실패 시 오류 번호 리턴pthread_mutex_unlock()
뮤텍스 잠금 해제
int pthread_mutex_unlock(pthread_mutex_t *mutex);
0
, 실패 시 오류 번호 리턴philo
philo/
0
이상 INT_MAX
이하)time_to_die
이상 경과된 경우must_eat
만큼 식사를 마친 경우포크, 프린트
👉 뮤텍스 타입으로 변수 선언
출력을 할 때 뮤텍스를 사용하지 않으면 시간 순서가 뒤죽박죽으로 출력되는 경우가 발생함
모든 조건을 만족해야 함
👉 모든 조건을 만족할 가능성이 있으므로 교착 상태 발생 가능
상호 배제와 선점 불가는 없으면 안 되는 조건
홀수 번부터 양쪽 포크가 있는 경우 식사를 하게 하고, 짝수 번은 잠시 대기하도록 하면 기아 현상을 예방할 수 있음
👉 스레드가 홀수 개인 경우 대기 시간이 조금 더 발생하게 되지만 스레드의 홀짝에 상관 없이 식사를 하는 순서가 보장됨
https://bigpel66.oopy.io/library/42/inner-circle/9
https://youtu.be/YAP0Bv_aQl8
비주얼라이저
테스터