발단
Valgrind를 통해 지금까지 작성한 다중스레드 프로그램을 확인하면서 이상한 점을 발견했다. 가장 기초적인 프로그램에서 조차 메모리 누수가 발생했다! 이유를 찾아 검색하던 도중 배운게 꽤 많아 이번 포스팅에서 정리하고자 한다.
결합 vs. 분리
기본적으로 pthread_create() 함수로 생성된 스레드는 결합 가능하다. 이것이 처음 작성한 다중스레드 프로그램에서 메모리 누수가 발생한 원인이었다! 스레드는 종료 시 관련 자원이 바로 해제되지 않기 때문에 부모 스레드가 pthread_join() 함수를 호출하여 자식 스레드가 종료될 때까지 대기해야 한다. 아니면, 스레드는 pthread_create() 함수에서 분리된 상태로 생성되거나 결합 가능한 상태로 생성되어도 pthread_detach() 함수로 분리된 상태로 설정되어야 한다.
pthread_join()
밑의 코드를 보면 pthread_attr() 함수가 없기 때문에 생성된 스레드는 결합 가능하다. 따라서 pthread_join() 함수를 메인 스레드에서 호출해야 한다. 가장 쉬운 방법은 당연히 바로 밑에 pthread_join() 함수를 호출하는 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | void create_thr() { int err; pthread_t tid; static char *in = "스레드 #1"; // 스레드 분기 지점. // 4번 인자는 반드시 힙 영역 혹은 데이터 영역 메모리. err = pthread_create(&tid, NULL, thr_fn, (void *)in); if (err != 0) { printf("오류 발생! 스레드 생성 실패, errno = %d\n", err); exit(EXIT_FAILURE); } // 결합 가능한 스레드의 자원은 부모 스레드가 해당 스레드에 결합할 때까지 해제되지 않는다. // 분리된 스레드의 자원은 해당 스레드가 종료되는 즉시 해제된다. // 결합 가능한 스레드는 실행 중에 분리된 스레드로 변환할 수 있으며 반대도 마찬가지다. // 기본적으로 스레드는 결합 가능한 모드에서 실행된다. // 자원을 해제하는 세 가지 방법. // 1. 스레드를 분리된 속성으로 생성한다(PTHREAD_CREATE_DETACHED). // 2. 스레드 생성 후 분리한다(pthread_detach()). // 3. 종료된 스레드와 결합한다(pthread_join()). pthread_join(tid, NULL); if (err != 0) { printf("오류 발생! 스레드 결합 실패, errno = %d\n", err); exit(EXIT_FAILURE); } } int main(int args, char *argv[]) { create_thr(); printf("메인 스레드 종료.\n"); // pause() 함수가 사용될 경우. // printf("메인 스레드 중지.") // 메인 스레드가 종료되어도 전체 프로세스를 종료하지 않으며 자식 스레드는 계속 실행된다. // create_thr() 함수에서 pthread_join() 함수가 사용될 경우 필요없다. pthread_exit(NULL); // pause() 함수가 주석으로 처리되면 메인 스레드 종료 시 모든 자식 스레드가 종료된다. // pause(); // 메인 함수에서 return을 사용하거나 exit() 함수를 호출하면 프로세스를 종료시킨다. exit(EXIT_SUCCESS); } | cs |
update: 2024.02.14
댓글 없음:
댓글 쓰기