변수
- number_of_philosophers : 철학자 수(+ 포크의 수)
- time_to_die : 지난 번 식사로부터 식사를 마칠 때까지 남은 시간.
- time_to_eat : 밥 먹는 데 걸리는 시간. 두 개의 포크를 사용해야 한다.
- time_to_sleep : 잠자는 데 걸리는 시간.
- number_of_times_each_philospher_must_eat : 옵션이며, 식사 횟수가 이 변수의 값과 같아지면 프로그램 종료.
허용 함수
usleep
마이크로초 단위로 측정한 간격 동안 쓰레드 실행을 일시 중단한다.
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
printf("1초마다 출력 합니다.\n");
for (int i = 0; i < 10; i++){
printf("%d초\n", i + 1);
usleep(1000000);
}
return (0);
}
gettimeofday
마이크로초 단위의 시간을 되돌려준다.
#include <sys/time.h>
#include <unistd.h>
struct timeval // 현재 시스템 시간을 저장하기위한 구조체
{
long tv_sec; // 초
int tv_usec; // 마이크로초
}
struct timezone // 타임존 설정을 위한 구조체 (현재 사용되지 않음)
{
int tz_minuteswest; // 그리니치 기준 서측으로 분(minute) 차(difference)
int tz_dsttime;
}
int gettimeofday(struct timeval *tv, struct timezone *tz);
성공 시 0, 실패 시 -1을 반환
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
int main(int argc, char *argv[])
{
struct timeval startTime, endTime;
double diff;
printf("작업 1\n");
gettimeofday(&startTime, NULL);
usleep(10000000);
printf("작업 2\n");
gettimeofday(&endTime, NULL);
diff = (endTime.tv_sec - startTime.tv_sec) + (endTime.tv_usec - startTime.tv_usec)/1000000;
printf("대기한 시간은 %f 초 입니다.\n", diff);
return (0);
}
pthread
POSIX 쓰레드의 약어. pthread는 모든 유닉스 계열 POSIX 시스템에서, 일반적으로 이용되는 라이브러리이다.
#include <pthread.h>
pthread_create
새로운 쓰레드를 생성하는 함수
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
pthread_t *thread : 쓰레드 식별자
const pthread_attr_t : 쓰레드 특성 지정
void *(start_routine)(void *) : 쓰레드가 실행되었을 때 시작할 함수
void *arg : 쓰레드가 실행되었을 때 시작할 함수의 매개변수
성공 시 0 반환, 실패 시 아래 에러들을 반환
- [EAGAIN] : The system lacked the necessary resources to create another thread, or the system-imposed limit on the total number of threads in a process
- [PTHREAD_THREADS_MAX] : would be exceeded.
- [EPERM] : The caller does not have appropriate permission to set the required scheduling parameters or scheduling policy.
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdlib.h>
#include <pthread.h>
void *t_func(void *data)
{
pid_t pid; // process id
pthread_t tid; // thread id
pid = getpid(); // process 식발자 가져오기
tid = pthread_self(); // thread 식별자 가져오기
char *t_name = (char *)data;
int i = 0;
while (i < 3)
{
printf("[%s] pid:%u, tid:%x --- %d\n",
t_name, (unsigned int)pid, (unsigned int)tid, i);
i++;
usleep(1000000); // 1초 대기
}
}
int main(int argc, char *argv[])
{
pthread_t thrd[2];
int tid;
int status;
char *t1 = "philo1"; // 1번 쓰레드 이름
char *t2 = "philo2"; // 2번 쓰레드 이름
char *tm = "main"; // 메인 쓰레드 이름
usleep(1000000);
// 1번 쓰레드 생성
tid = pthread_create(&thrd[0], NULL, t_func, (void *)t1);
if (tid < 0) // 쓰레드 생성 실패시 -1을 반환
{
printf("error\n");
exit(0);
}
// 2번 쓰레드 생성
tid = pthread_create(&thrd[1], NULL, t_func, (void *)t2);
if (tid < 0)
{
printf("error\n");
exit(0);
}
// main 함수에서도 쓰레드에서 돌아가고 있는 동일한 함수 실행
t_func((void *)tm);
// 1, 2번 쓰레드 종료를 기다림
pthread_join(thrd[0], (void **)&status);
pthread_join(thrd[1], (void **)&status);
return (0);
}
pthread_join
특정 쓰레드가 종료되기까지 기다린 후 쓰레드가 종료되면 실행한다.
첫 번째 매개변수는 쓰레드, 두 번째 매개변수는 해당 쓰레드 함수의 리턴값이다.
join된 쓰레드는 모두 반납된 쓰레드로 간주하며, 모든 자원을 반납하게 된다.
#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);
성공 시 0을 반환하고 실패 시 아래를 반환한다.
- [EINVAL] : The implementation has detected that the value specified by thread does not refer to a joinable thread
- [ESRCH] : No thread could be found corresponding to that specified by the given thread ID, thread
- [EDEADLK] : A deadlock was detected or the value of thread specifies the calling thread.
pthread_detach
특정 쓰레드를 해제한다.
일반적으로 pthread_create를 통해 생성한 쓰레드는 쓰레드 종료 시점에 자동으로 자원이 해제되는 것이 아니다.
이를 해제해주는 것이 pthread_join과 pthread_detach이다.
pthread_join과의 차이는 쓰레드가 종료될때까지 기다리는 것과, 기다리지 않고 즉시 쓰레드를 해제하는 것이다.
성공시 0을 반환하고 실패 시 아래를 반환한다.
- [EINVAL] : The implementation has detected that the value specified by thread does not refer to a joinable thread
- [ESRCH] : No thread could be found corresponding
#include <pthread.h>
int pthread_detach(pthread_t thread);
Mutex
mutex는 여러 개의 쓰레드가 공유하는 데이터를 보호하기 위한 것이다.
어떤 코드 영역에 대해 한 번에 하나의 쓰레드만 실행가능하도록 만듦으로써 공유되는 자원을 공유한다.
pthread_mutex_init
mutex를 만든다.
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
- pthread_mutex_t *mutex : 초기화할 mutex
- const pthread_mutexattr_t *attr : mutex의 특성, 기본적으로 NULL
성공시 0을 반환하고, 실패시 아래를 반환한다.
- [EINVAL] : The value specified by attr is invalid.
- [ENOMEM] : The process cannot allocate enough memory to create another mutex.
pthread_mutex_lock & pthread_mutex_unlock
mutex 임계 구역 진입 시 그 코드 구역을 잠그고 여는 함수
한 쓰레드에서 lock을 했다면 다른 코드는 그 구역에 들어가기 위해 unlock을 할때까지 기다려야한다.
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
성공시 0을 반환하고, 실패시 아래를 반환한다.
- [EINVAL] : The value specified by mutex is invalid.
- (lock)[EDEADLK] : A deadlock would occur if the thread blocked waiting for mutex.
- (unlock)[EPERM] : The current thread does not hold a lock on mutex.