개발 이야기

POSIX C pthread

ANDYLION 2020. 5. 7. 22:35
728x90
반응형

안녕하세요. 앤디라이언입니다.

 

 

pthreadposix thread를 줄여서 표현하며,

유닉스 계열 시스템에서 일반적으로 사용하는 thread 관련 표준 API입니다.

 

쓰레드를 생성하기 위해서는 pthread_create 메서드를 사용합니다.

//Create pthread
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);

/*param
*thread: 스레드 식별자 : 스레드가 성공적으로 생성되었을 때 생성된 스레드 식별을 위해 사용한다.
*attr: 스레드의 특성을 지정하기 위해 사용, 기본 스레드 특성 사용하는 경우는 항상 NULL로 지정한다.
start_routine : 분기시켜서 실행할 스레드 함수이다.
arg : 스레드 함수의 인자이다.
*/

 

쓰레드 생성이 성공하면 0을 리턴하고 그렇지 않으면 0이 아닌 수를 리턴합니다.

int thread_id;
thread_id = pthread_create(&thread, NULL, thread_proc, (void*) arg);
if(thread_id != 0)
{
	perror("Create thread error : ");
	exit(0);
}

 

위와 같이 예외 처리를 해주면 쓰레드 생성이 성공할 경우 0을 리턴하고

그렇지 않은 경우 에러 발생 메세지를 출력한 후 종료하게 됩니다.

 

다음으로 살펴 볼 내용은 pthread_join입니다.

pthread_join은 쓰레드를 종료하기 위해 기다리는 메서드입니다.

//pthread_joinn
int pthread_join(pthread_t thread, void **thread_return);

/*param
thread: 기다릴 스레드 식별자이다.
thread_return : 스레드의 리턴 값이다. 스레드 리턴 값이 NULL이 아닌경우 해당 포인터로 스레드 리턴 값을 받아올 수 있다.
*/

그럼 한번 pthread_join의 예를 한번 볼까요?

int thread_id;
thread_id = pthread_create(&thread, NULL, thread_proc, (void*)arg);
if(thread_id != 0)
{
	perror("Create Failed : ");
	exit(0);
}

//pthread_join -- no return param
pthread_join(thread, NULL);

쓰레드를 생성하고 생성된 쓰레드를 종료하기 위해 사용하는 예시입니다.

 

pthread_detach

//pthread_detach
int pthread_detach(pthread_t thread);

detach는 "떼어내다"라는 뜻을 가진 단어이며, 메인쓰레드에서 생성된 쓰레드를 분리시킬 때 사용합니다.

해당 쓰레드가 종료될 경우 join을 호출하지 않더라도 즉시 모든 자원이 해제됩니다.

//pthread_detach example
if(pthread_create(&thread, attr, thread_proc, arg)!=0)
{
...
}
pthread_detach(thread);

메인 쓰레드 안에 쓰레드가 하나 생성되었고,

그 쓰레드를 메인 쓰레드로부터 분리할 때 해당 쓰레드를 pthread_detach로 떼어내면

메인쓰레드와 독립적으로 운영되며 공유되었던 모든 자원을 사용할 수 없습니다.

 

pthread_exit

 

//pthread_exit
void pthread_exit(void *retval);

현재 실행중인 스레드를 종료하려고 할 때 사용합니다.

만약 pthread_cleanup_push가 정의되어 있다면,

pthread_exit가 호출될 경우 cleanup handler가 호출됩니다.

cleanup_handler는 메모리를 정리하는 작업을 합니다.

void *thread_proc(void *arg)
{
	static int retval = 777;
	printf("thread loop\n");
	pthread_exit((void*)&retval);
}

int main(void)
{
	int thread_id;
	pthread_t thread;
	void *tret = NULL;
	thread_id = pthread_create(&thread, NULL, thread_proc, NULL);
	if(thread_id != 0)
	{
		perror("create thread error : ");
		exit(0);
	}
	pthread_join(thread, &tret);
}

5) Cleanup push & pop

//pthread_cleanup_push
void pthread_cleanup_push(void (*routine) (void*), void *arg);

Cleanup handler를 설치하기 위해서 사용됩니다.

pthread_exit가 호출되어 스레드가 종료될 때

cleanup_push를 사용하여 설치된 함수를 호출합니다.

스레드 루틴이 종료될 때 호출되는 함수

Cleanup handlers는 주로 자원을 되돌려주거나 mutex 잠금등을 해제하는 용도로 사용됩니다.

//pthread_cleanup_pop
void pthread_cleanup_pop(int execute);

설치된 cleanup handlers를 제거하기 위해 사용합니다.

만약 execute가 0이라면, pthread_cleanup_push에 의해 설치된 cleanup_handler를 실행하지 않고 삭제만 시킵니다.

만약 0이 아니라면, cleanup_handler를 실행시키고 삭제한다.

void cleanup_ex1(void *arg)
{
	printf("cleanup_thread1\n");
}
void cleanup_ex2(void *arg)
{
	printf("cleanup_thread2\n");
}

void *start_thread(void *arg)
{
	printf("start threading...\n");
	pthread_cleanup_push(cleanup_ex1, NULL);
	pthread_cleanup_push(cleanip_ex2, NULL);

	sleep(5);

	printf("end threading...\n");

	pthread_cleanup_pop(0);
	pthread_cleanup_pop(0);

	return NULL;
}

주의할 점은 항상 Sync에 주의해야합니다.

Stack type으로 FILO (First In Last Out) 이기때문에

종료는 핸들러가 마지막에 잡고 있는 놈부터 종료시켜야 합니다.

pthread_self

//pthread_self
pthread_t pthread_self(void);

현재 스레드의 식별자를 리턴합니다.

void *thread_proc(void* arg)
{
	pthread_t id;
	id = pthread_self();
	printf("thread_id : %ud\n",(int) id);
	return NULL;
}

 현재 쓰레드 id를 확인하는 경우 사용됩니다.

 

이번 내용은 pthread에 대해 알아봤습니다. 

다음은 임계영역에 대한 pthread_mutex에 대해 알아보겠습니다.

 

from 앤디라이언 (Andy Lion)

728x90
반응형
SMALL

'개발 이야기' 카테고리의 다른 글

IPC 종류와 특징  (0) 2020.05.08
POSIX pthread_mutex  (0) 2020.05.07
POSIX C  (0) 2020.05.07
[파이썬 완전정복] 변수의 활용 연습하기  (0) 2020.05.04
[파이썬 완전정복] 데이터는 변수에게  (0) 2020.05.04