Pthread(Create)

Pthread
thread Standard API
    POISX 스레드 또는 Pthread(피-스레드)라고 부른다.
Pthread API
저수준 API로 100여개의 함수 제공
복잡하지만, 유닉스 시스템 핵심 스레딩 라이브러리
다른 스레딩 솔루션도 결국은 Pthread 기반으로 구현되어 있다.
Pthread Library <pthread.h>
모든 함수는 pthread_로 시작
크게 두 가지 그룹의 함수가 있다
    스레드 관리: 생성, 종료, 조인, 디태치 함수 등
    동기화: 뮤텍스(상호배제) 등 동기화 관련 함수
기본 라이브러리(glibc)와 분리된 libpthread 라이브러리에 pthread가 구현되어 있다.
컴파일시 명시적으로 -pthread 옵션이 필요함

$gcc -pthread test.c -o test
스레드 생성
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void* (*start_routine)(void*), void* arg);
//ex)
pthread_t thread1;
void *thread_function(void *ptr);
ret=pthread_create(&thread1, NULL, thread_function, (void*)message1);
thread: 생성된 스레드 식별자(스레드 개수만큼 필요하다.)
attr: 스레드 특정 설정(기본 NULL)
start_routine: 스레드 함수(스레드로 분기해서 실행할 함수)
arg: 스레드 함수 인자(start_routine, 스레드 함수의 인자)

return: 스레드 생성 성공시 1, 실패시 0
스레드 종료
void pthread_exit(void *retval);
//exit , NULL 0
//exit ,
//ex)
pthread_exit(NULL); // (void *retval)
스레드 조인
int pthread_join(pthread_t thread, void** thread_return);
//ex)
pthread_join(p_thread, (void*)&status);
printf("thraed_join: %d\n", status);
thread: 기다릴 스레드 식별자
thread_return: 스레드의 리턴 값을 가져올 포인터

p_thread 식별자를 가진 스레드의 종료를 기다리고, status 포인터로 종료값을 가지고온다.
스레드 분리
pthread_join를 기다리지 않고, 즉시 관련 리소스를 해제(free)
    pthread를 기다리지 않고, 종료 즉시 리소스를 해제
int pthread_detach(pthread_t thread);
// 0, ()
thread: detach할 스레드 식별자
pthread_join과 pthread_detach 차이점
pthread_join은 메인스레드에서 스레드 종료후 상태값을 수집하고, 추가 처리를 할 수 있지만,
pthread_detach는 스레드가 종료된 후, 바로 리소스가 해제된다.

실행측면에서는 pthread_join은 해당 스레드가 종료되지 않으면, 코드가 pthread_join에서 stop된다.
하지만, pthread_detach는 해당 스레드가 종료될 때가지 기다리지 않고, 바로 다음 명령어를 처리

pthread_join과 pthread_detach를 사용하지 않으면 스레드가 종료되어도 메모리가 해제되지 않음
pthreadsimple1.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_function(void* ptr){
char *message;
message=(char*)ptr;
printf("%s\n", message);
pthread_exit((void*)100);
}
int main(void){
pthread_t thread1, thread2;
const char* message1="Thread 1";
const char* message2="Thread 2";
int ret, status;
ret=pthread_create(&thread1, NULL, thread_function, (void*)message1);
printf("%d\n", ret);
if(ret==0){
printf("pthread_create returns %d\n", ret);
}else{
printf("pthread_create returns error: %d\n", ret);
exit(1);
}
ret=pthread_create(&thread2, NULL, thread_function, (void*)message2);
if(ret==0){
printf("pthread_create returns %d\n", ret);
}else{
printf("pthread_create returns error: %d\n", ret);
exit(1);
}
pthread_join(thread1, (void**)&status);
printf("thread1 returns: %d\n", status);
pthread_join(thread2, (void**)&status);
printf("thread2 returns: %d\n", status);
return 0;
}

0

pthread_create returns 0

pthread_create returns 0

Thread 2

Thread 1

thread1 returns: 100

thread2 returns: 100

pthreadsimple2.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
void *t_function(void* ptr){
char *message;
message=(char*)ptr;
printf("%s start\n", message);
sleep(5);
printf("%s end\n", message);
return 0;
}
int main(void){
pthread_t thread1, thread2;
const char* message1="Thread 1";
const char* message2="Thread 2";
int ret, status;
ret=pthread_create(&thread1, NULL, t_function, (void*)message1);
if(ret<0){
perror("thread create error");
}
pthread_detach(thread1);
ret=pthread_create(&thread2, NULL, t_function, (void*)message2);
if(ret<0){
perror("thread create error");
}
pthread_join(thread2, (void**)&status);
printf("thread2 returns: %d\n", status);
sleep(10);
return 0;
}

celina@ubuntuserver:~/celina/shell$ ./pthreadsimple3

Thread 2 start

Thread 1 start

Thread 2 end

thread2 returns: 0

Thread 1 end

만약 위의 pthread_join과 pthread_detach 순서를 바꾸면, 
thread1이 시작하고 pthread_join에서 thread1이 끝날 때까지 기다린다.
이후, thead2가 시작되고, pthread_detach가 되기 때문에
Thread 1 start가 출력 되고 sleep(5)에서 프로세스가 종료되어 버림(Thread 2 end 출력 안됨?!)