프로젝트 개요
Overview
이 과제를 수행하기 위해 알아야 할 사항 :
- 한 명 이상의 철학자들이 원탁에 앉아있습니다. 원탁의 가운데에는 스파게티가 담긴 큰 접시가 있습니다.
철학자들은 먹기, 생각하기, 잠자기 셋 중 하나의 행동을 취합니다.
먹는 도중에는 생각하거나 잠을 자지 않습니다. 생각하는 동안에도 먹거나 잠을 잘 수 없습니다.
당연히 잠자는 도중에도 밥을 먹거나 생각할 수 없습니다.
탁자 위에는 포크들이 있습니다. 포크의 수는 철학자의 수와 같습니다.
스파게티를 포크 하나로 먹기엔 불편하기에, 철학자는 양 손에 포크를 들고 먹습니다.
철학자가 밥을 다 먹으면, 포크들을 테이블에 도로 내려놓고 잠을 자기 시작합니다.
잠에서 깨면(잠을 다 자면), 생각하기 시작합니다.
철학자가 사망하면 시뮬레이션은 종료됩니다.
모든 철학자들은 먹어야 하며, 굶으면 안됩니다.
철학자들은 서로 대화할 수 없습니다.
철학자들은 다른 철학자가 언제 죽을 지 알아챌 수 없습니다.
철학자들이 죽는 걸 피해야 한다는 건 굳이 말 안해도 되겠죠?
Global Rules
전역 변수는 금지됩니다!
프로그램은 다음과 같은 인자를 가져야합니다: 철학자의 수(number_of_philosopher), 철학자의 수명(time_to_die), 밥 먹는데 걸리는 시간(time_to_eat), 잠자는 시간(time_to_sleep), [각 철학자가 밥을 먹는 최소 횟수(number_of_times_each_philosopher_must_eat)]
- 철학자의 수 : 철학자의 수와 포크의 개수
- 철학자의 수명(ms) : 철학자가 마지막으로 밥을 먹은 후 'time_to_die' 시간만큼 지나거나, 프로그램 시작 후 'time_to_die'시간만큼이 지났을 때 철학자가 다시 밥을 먹지 않으면 해당 철학자는 사망합니다.
- 밥 먹는데 걸리는 시간(ms) : 철학자가 밥을 먹는 데 걸리는 시간입니다. 해당 시간동안 철학자는 두 개의 포크를 집고 있어야 합니다.
- 잠자는 시간(ms) : 잠을 자는 데 필요한 시간입니다.
- 각 철학자가 밥을 먹는 최소 횟수 : 선택사항으로, 모든 철학자가 'number_of_times_each_philosopher_must_eat' 횟수만큼 밥을 먹었다면, 시뮬레이션이 종료됩니다. 해당 값이 명시되어 있지 않다면 철학자가 한 명이라도 사망할 때까지 시뮬레이션은 계속됩니다.
각 철학자에게는 1부터 'number_of_philosopher'만큼의 고유 번호가 부여됩니다.
철학자 1번은 철학자 'number_of_philosopher'번 옆에 앉습니다. 그 외에, N번 철학자는 N-1번 철학자와 N+1번 철학자 사이에 앉습니다. (원탁으로 둘러앉는다는 뜻)
프로그램의 로그 출력 : 철학자들의 모든 상태는 다음과 같은 형식에 맞춰 출력되어야 합니다.
(timestamp_in_ms는 현재 타임스탬프의 밀리초 단위로 표시되어야 하며, X는 철학자들의 번호로 대치)
- timestamp_in_ms X has taken a fork
- timestamp_in_ms X is eating
- timestamp_in_ms X is sleeping
- timestamp_in_ms X is thinking
- timestamp_in_ms X died
철학자의 상태는 다른 철학자들의 상태와 섞인 상태로 출력되면 안 됩니다.
철학자의 사망 시점과 이를 출력하기까지의 틈이 10ms 이상이 되면 안 됩니다.
다시 말하지만, 철학자들이 최대한 죽지 않아야 합니다.
Mandatory Part
Program name | philo |
Turn in files | Makefile, *.h, *.c, in directory philo/ |
Makefile | NAME, all, clean, fclean, re |
Arguments | number_of_philosophers time_to_die time_to_eat time_to_sleep [number_of_times_each_philosopher_must_eat] |
External functs. | memset, printf, malloc, free, write, usleep, gettimeofday, pthread_create, pthread_detach, pthread_join, pthread_mutex_init, pthread_mutex_destroy, pthread_mutex_lock, pthread_mutex_unlock |
Libft authorized | No |
Description | 쓰레드와 뮤텍스를 사용한 철학자 문제 |
필수파트의 특수한 규칙은 다음과 같습니다 :
각 철학자는 쓰레드여야 합니다.
두 철학자 사이에 한 개의 포크가 존재하므로, 철학자가 여러 명일 경우 각 철학자의 왼쪽과 오른쪽에 포크가 하나씩 존재해야 합니다. 만약 철학자가 딱 한 명이라면, 테이블에는 딱 한 개의 포크가 있어야 합니다.
철학자가 포크를 복제하는 것을 막기 위해, 각 포크의 현재 상태를 뮤텍스를 이용하여 보호해주어야 합니다.
식사하는 철학자 문제에 대하여 (The Dining-Philosophers Problem)
식사하는 철학자 문제는 고전적인 프로세스 동기화 문제들 중 하나이다.
위 그림은 철학자 문제 속 식사하는 철학자들의 상황이다.
원형테이블을 서로 공유하며 철학자가 생각할 때에는 다른 동료들과 상호작용하지 않는다.
포크를 자원에 비유하고 철학자들을 프로세스(42서울 과제에서는 쓰레드)라고 생각하면 쉽다.
프로세스(쓰레드)가 실행되는 동안 자원들을 확보해 실행하고, 실행되는 동안에는 다른 프로세스(쓰레드)가 접근할 수 없도록 보호해야하며 자원을 다 쓴 후에는 다른 프로세스(쓰레드)가 쓸 수 있도록 다시 되돌려놓아야 하는 것이다.
철학자가 밥을 먹어야 할 때, 각 철학자들의 사이에 있는 포크를 공유하게 되는데 이때 임계구역 문제(Critical-Section Problem)이 발생할 수 있다.
이러한 임계구역 문제를 해결하기 위한 하드웨어 기반 해결책은 매우 복잡할 뿐만 아니라 응용 프로그래머는 사용할 수가 없다. 대신 운영체제 설계자들은 임계구역 문제를 해결하기 위한 소프트웨어 도구들을 개발하였고, 그 중 가장 간단한 도구가 mutex(mutex exclusion) 락이며, mutex와 유사하게 동작하지만 프로세스들이 자신들의 행동을 더 정교하게 동기화 할 수 있는 방법을 제공하는 강력한 도구가 세마포(semaphores)이다.
필수 개념 정리
Threads
요즘의 현대 운영체제에서는 한 프로세스가 다중 스레드를 포함하는 특성을 제공한다. 다중 스레드를 포함하는 시스템은 대표적으로 Pthreads API나 Windows, Java Thread Library가 있다.
쓰레드는 CPU 이용의 기본 단위이다. 쓰레드는 쓰레드 ID, 프로그램 카운터(PC), 레지스터 집합, 스택으로 구성된다.
쓰레드는 같은 프로세스에 속한 다른 쓰레드와 코드, 데이터 섹션과 열린 파일, 시그널 같은 운영체제 자원들을 공유한다. 프로세스가 다수의 제어 쓰레드를 가진다면, 프로세스는 동시에 하나 이상의 작업들을 수행할 수 있다.
다중 쓰레드 프로그래밍의 장점은 다음과 같이 큰 부류로 나눌 수 있다.
- 응답성(Responsiveness) : 예를 들어 대화형 응용을 다중쓰레드화하면 응용 프로그램의 일부분이 봉쇄되거나, 또는 응용 프로그램이 긴 작업을 수행하더라도 프로그램의 수행이 계속되는 것을 허용함으로써, 사용자에 대한 응답성을 증가시킨다. 이 특징은 사용자 인터페이스를 설계하는 데 있어 특히 유용하다. 예로, 시간이 많이 걸리는 연산을 단일 쓰레드 프로세스가 처리할 때는, 연산이 처리되는 동안 다른 일을 못한다. 반면 시간이 많이 걸리는 연산을 별도의 쓰레드에서 실행시킨다면 다른 쓰레드에서 다른 작업을 수행할 수 있다.
- 자원 공유(Resource sharing) : 프로세스는 공유 메모리와 메시지 전달 기법을 통하여만 자원을 공유할 수 있다. 이러한 기법은 프로그래머에 의해 명시적으로 처리되어야 한다. 그러나 쓰레드는 자동적으로 그들이 속한 프로세스의 자원들과 메모리를 공유한다. 코드와 데이터 공유의 이점은 한 응용 프로그램이 같은 주소 공간 내에 여러 개의 다른 작업을 하는 쓰레드를 가질 수 있다는 점이다.
- 경제성(Economy) : 프로세스 생성을 위해 메모리와 자원을 할당하는 것은 비용이 많이 든다. 쓰레드는 자신이 속한 프로세스의 자원들을 공유하기 때문에, 쓰레드를 생성하고 문맥 교환하는 것이 보다 더 경제적이다. 오버헤드를 정확히 측정하는 건 어려울 수 있지만, 일반적으로 쓰레드를 사용하는 것보다 새로운 프로세스를 생성하고 관리하는 것이 훨씬 더 많은 시간과 비용을 소모한다. 예를 들어 Solaris에서는 프로세스를 생성하는 데 걸리는 시간이 쓰레드를 생성하는 데 걸리는 시간보다 약 30배 정도 오래 걸리며, 문맥 교환 시간은 5배 정도 오래 걸렸다.
- 규모 적응성(Scalability) : 다중 쓰레드의 이점은 다중 처리기 구조에서 더욱 증가할 수 있다. 다중 처리기 구조에서는 각각의 쓰레드가 다른 처리기에서 병렬로 수행될 수 있기 때문이다. 단일 쓰레드 프로세스는 처리기가 아무리 많더라도 제어 쓰레드가 하나기 때문에 오직 한 처리기에서만 실행된다. 즉 다중 쓰레드 환경에서는 단일 쓰레드일 때보다 병행 실행을 훨씬 더 향상시킬 수 있는 기법을 사용할 수 있다는 것이다.
병렬 실행 vs 병행 실행?
원어인 영어로 나타내면 그 차이가 더욱 명확하다.
병렬 실행은 Parallelism, 병행 실행은 Concurrenct execution이다.
하나 이상의 task를 동시에 수행할 수 있는 시스템에 대해 병렬적이라고 말한다. 대조적으로 병행 실행 시스템은 모든 task를 한번씩 진행하게끔 함으로써 하나 이상의 task를 지원한다.
따라서 병렬 실행 없이 병행 실행하는 것이 가능하다.


병렬 실행의 유형에도 데이터 병렬 실행과 태스크 병렬 실행이 있지만.. philosopher 문제와 조금 동떨어진 감이 있어 빼도록 하겠습니다.
Pthreads
Pthreads는 POSIX(IEEE 1003.1c)가 쓰레드 생성과 동기화를 위해 제정한 표준 API이다. 이것은 쓰레드의 동작에 관한 명세일 뿐이지 그것 자체를 구현한 것은 아니다. 각 운영체제 설계자마다 나름대로 구현하였기 때문에 운영체제마다 구현 방식이 조금씩 다를 수 있다.
구현 방식을 살펴보자.
모든 Pthreads 프로그램은 pthread.h 헤더 파일을 포함해야 한다.
pthread_t는 pthread들의 자료형이다.
pthread_attr_t는 스레드 속성의 자료형이다. 각 쓰레드는 스택의 크기와 스케쥴링 정보를 포함한 속성의 집합을 갖는다.
pthread_attr_init()함수를 이용해 속성을 지정하는데, 속성을 따로 지정하지 않으면 디폴트 속성을 사용한다.
다음은 사용할 함수에 대한 정리이다.
① 별도의 쓰레드를 생성 : pthread_create
int pthread_create(pthread_t *th_id, const pthread_attr_t *attr, void* 함수명, void *arg);
인자 → pthread_t th_id : pthread 식별자로, thread 생성에 성공하면 thread 식별값이 주어진다.
pthread_attr_t *attr : 쓰레드의 속성에 관한 정보가 담겨있다.
void* 함수명 : 새로운 쓰레드가 실행을 시작할 함수의 이름 (pthread로 분기할 함수 이름)
void *arg : 분기할 때 쓰레드에게 넘겨줄 정보가 들어있는 인자의 값 (어떠한 자료형을 넘겨줄 지 모르기
때문에 void 타입이며 필요에 따라 구조체를 생성하여 인자를 여러 개 전달할 수 있다.)
반환값 → 반환값이 0이면 생성 성공, 0이 아니라면 생성 실패
프로그램은 main() 함수의 최초(부모) 쓰레드와 pthread_create로 만들어 인자 함수에서 실행되는 자식 쓰레드들을 가지게 된다.
② 쓰레드가 종료되면 자원 회수 : pthread_join
int pthread_join(pthread_t th_id, void** thread_return);
인자 → th_id : 어떤 쓰레드를 종료될 때까지 기다릴지 식별
void** thread_return : 쓰레드 함수의 리턴 값을 포인터로 받아온다. 쓰레드 함수의 리턴 값이 없을 경우 NULL
반환값 → 반환값이 0이면 자원 회수 성공, 아니면 실패
prhead_create를 사용한 후 pthread_join, pthread_exit, pthread_detach와 같은 스레드 종료 함수를 호출하지 않을경우, 스레드 실행 중에 main이 종료되어 에러가 발생한다.
③ 부모 쓰레드와 자식 쓰레드를 분리 : pthread_detach
int pthread_detach(pthread_t th_id);
인자 → 분리시킬 쓰레드의 식별자가 담겨있는 th_id
반환값 → 분리 성공하면 0 반환, 실패하면 에러코드 반환
일반적으로 pthread_create()로 쓰레드를 생성하면 해당 쓰레드가 종료되더라도 부모 쓰레드가 종료되지 않으면 사용한 자원들이 해제되지 않는다. 자원을 해제하려면 pthread_join 또는 pthread_detach를 써야한다.
pthread_join은 인자 중 쓰레드 함수의 반환 값이 있기 때문에 별도의 처리를 할 수 있다. 대신 쓰레드가 종료될 때까지 대기해야 함.
pthread_detach를 사용하면 해당 쓰레드가 부모로부터 독립되기 때문에 쓰레드를 생성한 부모 함수에서 기다릴 필요가 없어진다. 즉 함수에서 쓰레드를 생성한 후 종료를 기다리지 않고 다음 루틴으로 넘어갈 수 있게 한다.
프로세스 동기화(Process Synchronization)
협력적 프로세스는 시스템 내에서 실행 중인 다른 프로세스의 실행에 영향을 주거나 영향을 받는 프로세스이다. 협력적 프로세스는 논리 주소 공간(코드와 데이터)을 직접 공유하거나, 파일 또는 메세지에 의해 데이터의 공유가 허용된다.
전자(논리 주소 공간을 직접 공유하는 케이스)는 쓰레드에 해당한다.
이 때, 공유 데이터에 대해서 동시에 접근하는 방법은 데이터의 비일관성을 초래할 수 있다.
그렇기 때문에 mutex lock 또는 세마포를 사용하여 데이터의 일관성을 유지하는 프로세스 동기화가 필요하다.
앞에서 말했던 데이터의 비일관성을 자세히 설명하면, 동시에 여러 개의 프로세스가 동일한 자료를 접근하여 조작하고, 그 실행 결과가 접근이 발생한 특정 순서에 의존하는 상황을 경쟁 상황(race condition)이라고 한다.
위와 같은 경쟁 상황으로부터 보호하기 위해, 프로그래머들은 한 순간에 하나의 프로세스만이 변수나 논리 공간을 조작하도록 보장해야 한다. 이러한 보장을 위해 프로그래머는 어떤 형태로든 프로세스들이 동기화 되도록 할 필요가 있다.
운영체제의 여러 부분에서 자원을 조작하기 때문에 위와 같은 상황은 빈번하게 발생한다.
특히, 다중쓰레드 응용에서는 자원을 공유할 가능성이 매우 높은 여러 쓰레드가 서로 다른 처리 코어에서 병렬로 실행된다. 이번 과제 philosopher 문제에서는 각각의 쓰레드들의 실행에서 기인한 수정이 서로 간에 영향을 주지 않아야하므로 프로세스 동기화(쓰레드 동기화)를 처리하는 게 중요 목적이라고 할 수 있다.
임계구역 문제(The Critical-Section Problem)
임계구역 문제는 프로세스들이 협력할 때 사용할 수 있는 프로토콜을 설계하는 것이다.
임계구역(critical section)이란 다른 프로세스와 공유하는 변수를 변경하거나, 테이블을 갱신하거나 파일을 쓰거나 하는 등의 작업을 수행할 수 있는 코드 부분을 말한다.
데이터의 비일관성을 막기 위해 두 프로세스는 동시에 그들의 임계구역 안에서 실행할 수 없어야 한다. 각 프로세스는 자신의 임계구역으로 진입하려면 진입 허가를 요청받아야 한다. 이러한 요청을 구현하는 코드 부분을 진입 구역(entry section)이라고 부른다. 임계구역 뒤에는 퇴출 구역(exit section)이 뒤따라올 수 있다. 코드의 나머지 부분들은 총칭하여 나머지 구역(remainder section)이라고 부른다.
do {
// entry section
critical section
// exit section
remainder section
} while (TRUE);
임계구역 문제에 대한 해결안은 다음의 세 가지 요구조건을 충족해야 한다.
- 상호 배제(mutual exclusion) : 프로세스 Pi가 자신의 임계구역에서 실행된다면, 다른 프로세스들은 각자의 임계구역에서 실행될 수 없다.
- 진행(progress) : 임계구역에서 실행하고 있는 프로세스가 없고 그리고 그들 자신의 임계구역으로 진입하려고 하는 프로세스들이 있다면, 나머지 구역에서 실행 중이지 않은 프로세스들만 임계구역 진입 순서에 포함될 수 있으며, 이러한 순서를 만드는 작업은 무한정 연기될 수 없다.
- 한정된 대기(bounded waiting) : 프로세스가 자신의 임계구역에 진입하려는 요청을 한 후부터 그 요청이 허용될 때까지, 다른 프로세스들이 각각의 임계구역에 진입할 수 있는 횟수에는 한계가 있어야 한다.
임의의 한 순간에 많은 커널 모드 프로세스들이 운영체제 안에서 활성화 될 수 있다. 그 결과 운영체제를 구현하는 코드(커널 코드)는 경쟁 조건이 발생하기 쉽다.
예를 들어, 시스템의 모든 열린 파일의 리스트를 유지하는 커널 자료구조가 있다고 한다. 이 리스트는 새 파일이 열리거나 닫히면 수정되어야 한다(파일을 리스트에 추가하거나 리스트에서 삭제하는 action). 만약 두 프로세스가 동시에 파일을 열려고 한다면, 리스트에 대한 개별적인 갱신은 경쟁 조건을 일으킬 수 있다. 경쟁 조건이 발생하기 쉬운 다른 커널 자료구조로는 메모리 할당을 관리하는 자료구조, 프로세스 리스트를 유지하는 자료구조, 인터럽트 처리를 위한 자료구조 등이 있다. 운영체제에서 이러한 경쟁 조건이 발생하지 않도록 보자아하는 것은 커널 개발자의 책임이다.
운영체제 내에서 임계구역을 다루기 위해서 선점형 커널과 비선점형 커널의 두 가지 일반적인 접근법이 사용된다.
선점형 커널 : 프로세스가 커널 모드에서 수행되는 동안 선점되는 것을 허용한다. 공유되는 커널 자료구조에서 경쟁 상황이 발생하지 않는다는 것을 보장하도록 신중하게 설계되어야 한다(SMP-Symmetric multiprocessing 구조에서 선점형 커널을 설계하는 것은 특히 어렵다. 이 환경에서는 서로 다른 처리기의 두 프로세스가 동시에 커널 모드에 있을 수 있기 때문이다). 하지만 대기 중인 프로세스에게 처리기를 양도하기 전에 오랫동안 실행할 위험이 적기 때문에 더 응답이 민첩하고, 그렇기 때문에 선점형 커널이 더 선호된다.
비선점형 커널 : 커널 모드에서 수행되는 프로세스의 선점을 허용하지 않고 커널 모드 프로세스는 커널을 빠져 나갈 때까지 또는 봉쇄될 때까지 또는 자발적으로 CPU의 제어를 양보할 때까지 계속 수행된다. 자료구조에 대한 겅쟁 상황을 염려할 필요는 없지만, 선점형 커널에 비해 속도가 다소 떨어진다.
Mutex Locks
위에서 언급했듯이 운영체제 설계자들이 임계구역 문제를 해결하기 위한 소프트웨어 도구들을 개발하고 그 중 가장 간단한 도구가 mutex lock이다. mutex라는 용어는 mutual exclusion의 축약 형태이다. 개발자들은 임계구역을 보호하고 따라서 경쟁 조건을 방지하기 위해 mutex lock을 사용한다. 즉, 프로세스는 임계구역에 들어가기 전에 반드시 락을 획득해야 하고 임계구역을 빠져나올 때 락을 반환해야 한다. 뮤텍스 락을 구현하기 위해서 사용할 함수들은 아래에 다른 함수들과 함께 따로 정리하겠다.
교착 상태와 기아(Deadlock and Starvation)
실행되고 있는 두 개 이상의 프로세스들이, 대기 중인 프로세스들 중 하나에 의해서만 야기될 수 있는 사건을 무한정 기다리는 상황이 발생할 수 있다. 여기서 사건이라 함은 락을 건내주는 함수의 실행을 말한다. 이런 상태에 도달했을 때, 이들 프로세스들을 교착 상태(Deadlock)에 빠졌다고 한다.
다시 말하면 한 집합 내의 모든 프로세스들이 그 집합 내의 다른 프로세스만이 유발할 수 있는 함수 실행을 기다릴 때, 이 프로세스들의 집합이 교착 상태에 있다고 말한다. 여기서 주의깊게 봐야할 사건들은 자원의 획득과 방출이다. 데드락에 대해 설명하려면 따로 한 챕터를 빼서 설명해야 하기 때문에 이번 포스팅에서는 간단하게만 설명하였다.
교착 상태와 연관된 다른 문제는 무한 봉쇄(infinite blocking) 또는 기아(starvation)로서, 이것은 프로세스들이 무한정 대기하는 것이다. 기아(starvation)는 프로세스가 실행되는 데 필요한 자원들을 할당받지 못한 채로 계속 기다리고 있는 상황을 말한다. 무한 봉쇄는 프로세스들이 기다리고 있는 순서인 대기 큐에서 프로세스들을 후압 선출(LIFO) 순서로 제거할 경우 발생할 수 있다.
필요한 함수 정리
① 코드 실행 보류 : usleep
#include <unistd.h>
int usleep(useconds_t usec);
이전 과제 minitalk을 수행할 때에도 썼던 함수인데, 인자로 마이크로초 단위의 시간을 입력하면 그 시간동안 코드 실행이 멈춘다. usleep(10000000)을 할 경우 다음 흐름의 코드가 10초 후에 수행된다.
sleep과 usleep이 있으며, usleep은 초 단위를 더욱 세밀하게 조절하기 위해 사용한다.
② 시스템 시간을 반환 : gettimeofday
#include <sys/time.h>
#include <unistd.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
인자 → timeval *tv : 현재 시스템 시간을 저장하기 위한 구조체이다.
struct timeval
{
long tv_sec; // 초
long tv_usec; // 마이크로초
}
timezone *tz : 타임존을 설정하기 위한 구조체이다. 하지만 현재 이 구조체는 사용되지 않으며,
앞으로도 지원되지 않을 예정이다. 두번째 인자는 그냥 NULL을 넣으면 된다.
반환값 → 반환에 성공하면 0, 실패하면 -1을 리턴한다.
time(2)함수와 매우 비슷하지만 마이크로초 단위의 시간까지 출력할 수 있다.
③ 동적으로 mutex 초기화 : pthread_mutex_init
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr *attr);
인자 → pthread_mutex_t *mutex : 초기화시킬 mutex 객체 지정
pthread_mutex_attr *attr : 초기화 시킬 때 attr를 이용하여 mutex의 특징을 정의할 수 있다. NULL을 사용하면 디폴트 특징.
반환값 → 언제나 0을 리턴한다.
④ 동적으로 만들어진 mutex 객체를 파기 : pthread_mutex_destroy
int pthread_mutex_destroy(pthread_mutex_t *mutex);
인자 → 첫번째 인자인 mutex가 가리키는 mutex 객체를 파기한다.
반환값 → 성공하면 0, 실패하면 오류코드를 반환.
⑤ 임계구역 진입 제어 : pthread_mutex_lock, pthread_mutex_unlock
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
인자 → 첫번재 인자는 잠구거나 풀기 위한 mutex 객체.
반환값 → 실행에 성공하면 0을 반환, 실패해다면 0이 아닌 수를 리턴한다.
쓰레드가 mutex를 이용하여 임계 구역을 진입할 때 그 코드 구역을 잠그고 다시 임계구역이 끝날 때 다시 풀어 다음 쓰레드가 진입할 수 있게 한다.
pthread_mutex_lock이 어떤 쓰레드에서 호출되어 lock이 걸렸을 때, 다른 쓰레드가 임계구역에 진입하기 위해 pthread_mutex_lock을 호출했다면 그 쓰레드는 이전의 쓰레드가 임계 구역에서 나올 때까지(pthread_mutex_unlock을 할 때까지) 기다려야 한다.
참고
Operating System: Concepts
https://redcoder.tistory.com/89
[C] pthread의 기본 구조와 함수들
기본적으로 프로그래밍에 있어서, 효율은 매우 중요하다. 특히 우리가 컴퓨터를 하거나 스마트폰을 할 때 음악을 들으면서, 검색을 할 수 있는 이유는 주어진 자원을 최대한 활용하기 때문인데
redcoder.tistory.com
https://hydroponicglass.tistory.com/298
[C, C++] Pthread로 스레드 구현
목적 a와 b를 각각 무한히 출력하는 가장 기본적인 스레드 A와 B를 구현한다. 스레드 구현 헤더파일 #include #include 스레드 구현부 void *threadA() { while(1) { printf("a\n"); } } void *threadB() { while(..
hydroponicglass.tistory.com
https://blog.daum.net/yykoo/79
pthread_join과 pthread_detach 차이
프로세서에 thread를 적용하여 구현할때 pthread_create 이후 이 thread함수의 종료를 기다릴때 주로 pthread_join 함수를 사용합니다. -------------------- Sample.1 start ---------------------- void *t_func..
blog.daum.net
https://www.joinc.co.kr/w/man/2/gettimeofday
gettimeofday - 현재 시간을 가져오고 시스템의 시간값을 설정한다.
현재 시간을 가져오고 시스템의 시간값을 설정한다. 1.2. 설명 gettimeofday()은 time(2)와 매우 비슷하지만 마이크로초 단위의 시간 까지 되돌려준다. 현재는 time(2)를 대신해서 쓰이고 있으며, 가능한
www.joinc.co.kr
'42seoul' 카테고리의 다른 글
집컴(Linux)에 노미넷 설치하는 방법 (norminette v3) (0) | 2022.09.01 |
---|---|
Push Swap : 가장 작은 인자 정렬 프로그램을 계산하기 (0) | 2022.04.02 |
So Long : miniLibX로 만드는 간단한 2D 게임 (0) | 2022.04.02 |
Minitalk : 서버와 클라이언트 간 문자열 교환 프로그램(using SIGNAL) (0) | 2022.04.02 |
printf : 사용자가 format을 지정해 출력할 수 있는 함수 (0) | 2022.04.02 |