-
[Linux] 멀티 스레드와 싱글 스레드 성능 비교하기 _pthreadLinux 2023. 4. 14. 16:33728x90반응형
pthread를 이용해서 멀티 스레드와 싱글 스레드 성능 비교하기
이번 운영체제 과제는 멀티 스레드가 싱글 스레드보다 빠르게 작업 수행이 가능하다는 것을 증명하는 코드를 구현하는 거였어요. 🤔
아래는 과제의 본문입니다.
교수님께서 부가적으로 말씀하신게 sleep()은 쓰지 말라고 하시더군요
🍊 pthread와 관련된 함수
📍 pthread_craete()
pthread_create() : 새로운 스레드를 생성하는 함수
#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
- thread: 새로운 스레드의 식별자를 저장할 변수의 포인터입니다. pthread_t 타입입니다.
- attr: 새로운 스레드의 특성을 지정하는 pthread_attr_t 타입의 포인터입니다. 일반적으로 **NULL**을 사용하면 기본값이 사용됩니다.
- start_routine: 새로운 스레드가 실행할 함수의 포인터입니다. 이 함수는 반드시 void * 타입의 인자를 받아서 void * 타입으로 반환해야 합니다.
- arg: start_routine 함수에 전달될 인자를 지정하는 void * 타입의 포인터입니다.
pthread_create() 함수는 호출되면 새로운 스레드를 생성하고, start_routine 함수를 실행합니다. start_routine 함수가 실행되면서 arg 인자를 전달받습니다.
📍 pthread_join()
pthread_join() 함수는 생성된 스레드가 종료될 때까지 대기하고, 스레드의 실행이 완료될 때까지 현재 스레드를 차단(block)합니다.
int pthread_join(pthread_t thread, void **retval);
- thread: 대기하고자 하는 스레드의 식별자
- retval: 종료된 스레드가 반환하는 값에 대한 포인터
pthread_join()의 역할
- 대기: pthread_join() 함수는 인자로 전달된 스레드 식별자(thread identifier)가 가리키는 스레드가 종료될 때까지 대기합니다.
- 스레드 반환값 수집: pthread_join() 함수는 스레드가 반환하는 값에 대한 포인터를 인자로 받습니다. 이 포인터는 종료된 스레드에서 pthread_exit() 함수를 호출할 때 전달한 값에 대한 포인터입니다. 이 함수가 반환한 값은 호출한 스레드에서 스레드의 반환값을 수집하는 용도로 사용될 수 있습니다.
- 스레드 자원 해제: pthread_join() 함수는 종료된 스레드의 자원을 해제합니다. 이는 스레드의 스택(stack)과 같은 자원을 해제하여, 메모리 누수를 방지하는 역할을 합니다.
이 포인터는 종료된 스레드에서 pthread_exit() 함수를 호출하여 전달된 값을 받습니다.
📍 pthread_mutex_init()
pthread_mutex_init() 함수는 뮤텍스(mutual exclusion, 상호배제)를 초기화하는 데 사용됩니다.
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
- mutex: 초기화하려는 뮤텍스의 포인터입니다. 이 함수를 호출하여 뮤텍스를 초기화하면, 이 포인터가 가리키는 메모리에 뮤텍스 객체가 생성됩니다.
- attr: 뮤텍스의 속성을 설정하는 데 사용됩니다. 이 인자를 NULL로 전달하면 기본 속성으로 뮤텍스를 초기화합니다.
🍊 mutex와 관련된 함수
📍 pthread_mutex_lock()
pthread_mutex_lock() 함수는 상호 배제를 위해 임계 구역을 보호할 때 사용하는 함수입니다. 이 함수를 통해 뮤텍스에 잠금을 걸어 다른 스레드가 접근하지 못하도록 합니다. 인자로는 잠금을 걸려는 뮤텍스의 포인터를 전달합니다.
📍 pthread_mutex_unlock()
pthread_mutex_unlock() 함수는 pthread_mutex_lock() 함수의 반대로, 뮤텍스에 잠금을 해제시키기 위한 함수입니다. 인자로는 마찬가지로 잠금을 해제하려는 뮤텍스의 포인터를 전달합니다.
📍 pthread_mutex_destroy()
pthread_mutex_destroy() 함수는 뮤텍스(mutual exclusion, 상호배제)를 파괴하는 함수입니다. 인자로는 삭제하려는 뮤텍스 포인터를 전달합니다. 이 함수를 통해 뮤텍스 객체를 소멸시킵니다.
🍊 코드로 구현해보자
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <sys/time.h> #define MAX_THREAD 8 // 스레드 개수 #define MAX_NUM 1000000000 // 합할 숫자의 최대값 /* 1부터 MAX_NUM 까지 모든 수를 합하는 동작을 멀티스레드와 싱글스레드로 각각 실행하여 성능을 비교하는 프로그램입니다. */ long sum = 0; long part = 0; pthread_mutex_t lock; // 상호 배제 보장을 위한 뮤텍스 사용 typedef struct { long threadSum; // 합산 결굇값 담을 변수 struct timeval timeval; // 시간 계산을 위한 timeval 변수 } Thread; // 구조체 정의 // 멀티 스레드 동작 수행을 위한 함수 void *sum_thread(void *arg) { long thread_part = part++; long local_sum = 0; for (long i = thread_part * (MAX_NUM / MAX_THREAD) + 1; i <= (thread_part + 1) * (MAX_NUM / MAX_THREAD); i++) { local_sum += i; } pthread_mutex_lock(&lock); // 임계 구역 보호를 위해 상호 배제 lock sum += local_sum; pthread_mutex_unlock(&lock); // Mutex lock 해제 return NULL; } // 싱글 스레드 실행 함수 Thread do_single_thread() { struct timeval start_time, end_time; // 시간 계산을 위한 시작 & 종료 변수 gettimeofday(&start_time, NULL); // 시간 측정 시작 pthread_mutex_lock(&lock); // 임계 구역 잠금 for (long i = 1; i <= MAX_NUM; i++) { sum += i; } pthread_mutex_unlock(&lock); // 임계 구역 해제 gettimeofday(&end_time, NULL); // 시간 측정 종료 // 구조체에 싱글 스레드 값 입력 Thread single_thread = { sum, // sum 값 대입 {.tv_sec = end_time.tv_sec - start_time.tv_sec, .tv_usec = end_time.tv_usec - start_time.tv_usec} // 측정 시간 대입 }; // 싱글 스레드 구조체 반환 return single_thread; } // 멀티 스레드 실행 함수 Thread do_multi_thread() { sum = 0; // 멀티 스레드 생성 pthread_t threads[MAX_THREAD]; struct timeval start_time, end_time; // 시간 계산을 위한 시작 & 종료 변수 gettimeofday(&start_time, NULL); // 시간 측정 시작 // 스레드 8개 생성 for (long i = 0; i < MAX_THREAD; i++) { pthread_create(&threads[i], NULL, sum_thread, NULL); } // 스레드 반환값 수집 for (long i = 0; i < MAX_THREAD; i++) { pthread_join(threads[i], NULL); } gettimeofday(&end_time, NULL); // 시간 측정 종료 // 구조체에 멀티 스레드 값 입력 Thread multi_thread = { sum, // sum 값 대입 { .tv_sec = end_time.tv_sec - start_time.tv_sec, .tv_usec = end_time.tv_usec - start_time.tv_usec } // 측정 시간 대입 }; // 멀티 스레드 구조체 반환 return multi_thread; } // 결과 출력 함수 void print_diff(Thread single_thread_processing_time, Thread multi_thread_processing_time){ printf("single_thread:\\n"); printf(" - 결과: %ld, 소요시간: %ld.%3d 초\\n\\n", single_thread_processing_time.threadSum, single_thread_processing_time.timeval.tv_sec, single_thread_processing_time.timeval.tv_usec); printf("multi_thread:\\n"); printf(" - 결과: %ld, 소요시간: %ld.%3d 초", multi_thread_processing_time.threadSum, multi_thread_processing_time.timeval.tv_sec, multi_thread_processing_time.timeval.tv_usec); } int main(int argc, char* argv[]) { pthread_mutex_init(&lock, NULL); // 뮤텍스 초기화 Thread single_thread_processing_time = do_single_thread(); // 싱글 스레드 함수 실행 Thread multi_thread_processing_time = do_multi_thread(); // 멀티 스레드 함수 실행 // 결과 출력 print_diff(single_thread_processing_time, multi_thread_processing_time); pthread_mutex_destroy(&lock); // 사용이 끝난 뮤텍스 제거 return 0; }
🍊 후기
조금의 시행착오가 있었지만 무사히 끝냈습니다. 역시 코딩은 재미있어요 ㅎㅅㅎ.
그리고 이번에 또 느낀 건 과제가 아니더라도 주석은 항상 달도록 습관으로 해둬야겠다고 생각했어요. 누구나 제 코드륵 술술 읽을 수 있도록 말이죠 🤔
LIST'Linux' 카테고리의 다른 글
[Linux] 공유 메모리(Shared Memory)로 채팅 프로그램 구현하기 _IPC (0) 2023.04.10