-
시스템 프로그래밍 실습 11주차 : PthreadsSystem Programming/Ubuntu Linux 2021. 11. 8. 09:45728x90
[목차]
- Process vs Threads
- Pthreads 관련 API 종류
- Pthreads의 데이터 타입과 속성
- Pthreads 다루기 (메소드)
- Creating Threads - 쓰레드를 생성한다
- Terminating Threads - 쓰레드를 종료한다
- Joining Threads
- Detaching Threads - 쓰레드를 메인 쓰레드에서 분리시킨다
1. Process vs Threads
- Process는 한 process에 한 주소 공간(address space) -> 각각의 process가 자신만의 data(전역 변수), stack, heap을 가지고 있다
- Threads는 address space를 공유할 수 있다 -> data와 heap 영역은 같은 주소 공간 내에서 공유하고, 자신만의 heap과 register는 따로 갖는다
- multiple processes와는 다르게 서로 공유하는 메모리 공간이 있어, pipe나 sockets등을 사용할 필요가 없다
2. Pthreads 관련 API 종류
- Thread management API (11주차)
- Mutex API (13주차)
: mutex 는 여러 개의 쓰레드가 공유하는 데이터를 보호하기 위해서 사용되는 도구로써, 보호하고자 하는 데이터를 다루는 코드영역을 단지 '한번에 하나의 쓰레드만' 실행가능 하도록 하는 방법으로 공유되는 데이터를 보호한다.
이러한 코드영역(하나의 쓰레드만 점유가능한)을 critical section 이라고 하며, mutex 관련 API 를 이용해서 관리할수 있다.- Conditional variable API (13주차)
: conditonal variable은 공유 데이터에 대한 특정 조건에 따라 Thread의 실행을 중지하거나 다시 실행하는 역할을 하는 동기화 장치다. 조건 변수에 대한 기본 연산은 1) 조건 변수에 시그널을 보낸다(특정 조건이 만족된 경우), 2) 조건 변수를 기다린다 (다른 쓰레드가 해당 조건 변수에 시그널을 보낼 때까지 쓰레드의 실행이 중지됨)
=> 조건 변수는 한 쓰레드가 조건 변수를 기다릴 준비를 하는 동안 (실제로 대기하기 전에) 다른 쓰레드가 해당 조건 변수에 시그널을 보내는 것과 같은 경쟁 상태를 방지하기 위해 항상 뮤텍스와 함께 사용되어야 한다.
3. Pthreads의 데이터 타입과 속성
=> pthread[_object]_t : [_object]에는 attr, mutex나 cond이 들어갈 수 있다 !
1) pthread_t / pthread_attr_t
2) pthread_mutex_t / pthread_mutex_attr_t
3) pthread_cond_t / pthread_cond_attr_t
* ) pthread_attr_t의 속성들
- pthread_attr_init : 쓰레드 속성 객체인 attr을 초기화
int pthread_attr_init(pthread_attr_t *attr);
- pthread_attr_destroy : pthread_attr_init에 의해 생성된 thread attribute 객체인 attr을 제거
int pthread_attr_destroy(pthread_attr_t *attr);
=> 쓰레드를 분리시키는 방법으로, pthread_detach() 함수 대신 '쓰레드 속성' 값을 주어 애초에 생성될때 detach 속성으로 생성되게 할 수 있다!
- pthread_attr_setdetachstate : 쓰레드의 상태를 PTHREAD_CREATE_JOINABLE 혹은 PTHREAD_CREATE_DETACHED 상태로 변경.
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
pthread_attr_t attr;
// JOINABLE 상태로 변경
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// DETACHED 상태로 변경
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);- pthread_attr_getdetachstate
#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> // 쓰레드 속성 ( pthread_attr_t ) 을 사용하여 // 종료시 자원 반납하는 쓰레드 생성 // 쓰레드 함수 // 5초간 머뭄뒤에 종료 void *t_function(void *data) { char a[100000]; // 자원 점유! static int num = 0; num = *((int *)data); printf("Thread Start\n"); sleep(5); printf("Thread end\n"); return (void*)# } int main() { pthread_t p_thread; pthread_attr_t attr; //쓰레드 속성값 int thr_id; int status; int a = 100; // '쓰레드 분리' 속성값 지정 : PTHREAD_CREATE_DETACHED pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 위 속성값과 함께 쓰레드 생성 printf("Before Thread\n"); thr_id = pthread_create(&p_thread, &attr, t_function, (void *)&a); if (thr_id < 0) { perror("thread create error : "); exit(0); } // pthread_detach() 없어도 쓰레드종료시 자동 종료 & 자원반납. // 쓰세드 속성값 삭제 pthread_attr_destroy(&attr); pause(); return 0; }
=>
Before Thread
Thread Start
Thread end
https://bitsoul.tistory.com/168?category=683199
4. Pthreads 다루기 (메소드)
=> compile할 때 반드시 -lpthread 옵션 줘야 한다!
1) Creating Threads - 쓰레드를 생성한다
#include <pthread.h> int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg);
• 별도의 작업없이 바로 실행되는 thread생성
• Parameters
– ‘thread’: 새로 만드려는 thread의 ID
– ‘attr’: 속성값, 보통 NULL값을 많이 준다.
– ‘start_routine’: 실행하려는 함수의 이름
– ‘arg’: ‘start_routine’에 들어갈 파라미터
• Return values
– 0 if successful, nonzero if unsuccessful#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> // 쓰레드 함수 void *t_function(void *data) { pid_t pid; // process id pthread_t tid; // thread id pid = getpid(); tid = pthread_self(); char* thread_name = (char*)data; int i = 0; while (i<3) // 0,1,2 까지만 loop 돌립니다. { // 넘겨받은 쓰레드 이름과 // 현재 process id 와 thread id 를 함께 출력 printf("[%s] pid:%u, tid:%x --- %d\n", thread_name, (unsigned int)pid, (unsigned int)tid, i); i++; sleep(1); // 1초간 대기 } } int main() { pthread_t p_thread[2]; int thr_id; int status; char p1[] = "thread_1"; // 1번 쓰레드 이름 char p2[] = "thread_2"; // 2번 쓰레드 이름 char pM[] = "thread_m"; // 메인 쓰레드 이름 sleep(1); // 2초 대기후 쓰레드 생성 // ① 1번 쓰레드 생성 // 쓰레드 생성시 함수는 t_function // t_function 의 매개변수로 p1 을 넘긴다. thr_id = pthread_create(&p_thread[0], NULL, t_function, (void *)p1); // pthread_create() 으로 성공적으로 쓰레드가 생성되면 0 이 리턴됩니다 if (thr_id < 0) { perror("thread create error : "); exit(0); } // ② 2번 쓰레드 생성 thr_id = pthread_create(&p_thread[1], NULL, t_function, (void *)p2); if (thr_id < 0) { perror("thread create error : "); exit(0); } // ③ main() 함수에서도 쓰레드에서 돌아가고 있는 동일한 함수 실행 t_function((void *)pM); // 쓰레드 종료를 기다린다. pthread_join(p_thread[0], (void **)&status); pthread_join(p_thread[1], (void **)&status); printf("언제 종료 될까요?\n"); return 0; }
=> 하나의 프로세스 (pid:3558) 에서 메인쓰레드를 포함한 3개의 쓰레드가 병렬 실행되고 있는 것이 확인된다
[thread_m] pid:3558, tid:c30a9740 --- 0
[thread_1] pid:3558, tid:c28be700 --- 0
[thread_2] pid:3558, tid:c20bd700 --- 0
[thread_1] pid:3558, tid:c28be700 --- 1
[thread_m] pid:3558, tid:c30a9740 --- 1
[thread_2] pid:3558, tid:c20bd700 --- 1
[thread_m] pid:3558, tid:c30a9740 --- 2
[thread_1] pid:3558, tid:c28be700 --- 2
[thread_2] pid:3558, tid:c20bd700 --- 2
언제 종료 될까요?https://bitsoul.tistory.com/157?category=683199
2) Terminating Threads - 쓰레드를 종료한다
#include <pthread.h> void pthread_exit(void* value_ptr);
• calling thread를 종료한다.
– ‘return’ 은 결국 암시적으로 pthread_exit를 사용한다.
– ‘value_ptr’: pthread_join이 해당 값을 받을 수 있도록 저장되는 곳#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> // 쓰레드 함수 // 1초단위로 화면에 출력 void *t_function(void *data) { static int retval = 999; int count = *((int *)data); int i = 0; while (1) { // i 값이 3 이 되면 '현재 쓰레드' 종료 if (i == count) { // 반환값 설정 pthread_exit((void*)&retval); } printf("Thread Running... %d : data=%d\n", i, count); i++; sleep(1); } } int main() { pthread_t p_thread; int thr_id; void *tret = NULL; int count = 3; //쓰레드 생성, count값을 쓰레드함수에 넘겨줌 thr_id = pthread_create(&p_thread, NULL, t_function, (void *)&count); if (thr_id < 0) { perror("thread create error : "); exit(0); } pthread_join(p_thread, &tret); // pthread_exit 의 반납값 출력 printf("thread exit code %d\n", *((int*)tret)); return 0; }
=>
Thread Running... 0 : data=3
Thread Running... 1 : data=3
Thread Running... 2 : data=3
thread exit code 999예제 1)
+) 추가적으로 pthread_cancel도 존재한다!
https://bitsoul.tistory.com/165?category=683199
3) Joining Threads - 쓰레드의 종료를 기다린다
#include <pthread.h> int pthread_join(pthread_t thread, void **value_ptr);
=> 특정 쓰레드가 종료하기를 기다렸다가, 쓰레드가 종료된 이후 다음 진행
• target thread가 종료될때까지 현재의 calling thread를 suspend한다.
– detached 처리되지 않은 thread의 resources는 다른 thread가 pthread_join를 사용하거나 전체 process가 종료되지 않는 이상 release되지 않음.
• Parameters
– ‘thread’: a target thread
– ‘value_ptr’: 리턴값이 들어갈 포인터의 포인터. null이면 상태값을 찾지도 않는다.
• Return values
– 0 if successful, nonzero if unsuccessful
• Example
– pthread_join(pthread_self()); (deadlock 생성)#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> // 쓰레드 함수 // 1초를 기다린후 (매개변수*매개변수)를 리턴합니다 void *t_function(void *data) { int num = *((int *)data); printf("num %d\n", num); sleep(1); num *= num; printf("쓰레드 함수 종료 합니다\n"); return (void *)(num); // warning 발생 } int main() { pthread_t p_thread; int thr_id; int result; int a = 200; thr_id = pthread_create(&p_thread, NULL, t_function, (void *)&a); if (thr_id < 0) { perror("thread create error : "); exit(0); } // 쓰레드 식별자 p_thread 가 종료되길 기다렸다가 // 종료후에 리턴값을 받아옵니다. pthread_join(p_thread, (void *)&result); printf("thread join : %d\n", result); printf("main() 종료\n"); return 0; }
=>
num 200
쓰레드 함수 종료 합니다
thread join : 40000
main() 종료예제 2)
https://bitsoul.tistory.com/160?category=683199
4) Detaching Threads - 쓰레드를 메인 쓰레드에서 분리시킨다
특정 쓰레드를 분리시킵니다.
'일반적'으로 쓰레드를 pthread_create() 를 사용하여 생성하면, 쓰레드가 종료되더라도 사용했던 모든 자원이 해제되지 않습니다.
반면 pthread_join() 을 사용하여 종료될때까지 기다렸다가 종료시점이 되면, 자원이 반납됩니다.
한편, pthread_detach() 함수는 pthread_join()을 사용하지 않더라도, 쓰레드 종료될때 모든 자원을 해제 됩니다#include <pthread.h> int pthread_detach(pthread_t thread);
• thread 내부옵션을 변경하여 해당 thread가 resource를 release하도록 한다.
– 만약 thread가 detached thread가 아니라면, 해당 thread는 exit될때 resource를 release하지 않는다.
– 해당 함수를 통해 detached thread가 되면, exit할 때 그들의 정보를 기록하지 않는다.
– (이미 resource를 release했기 때문에)
– Returns 0 if successful, nonzero if unsuccessful#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> // 쓰레드 함수 // 5초간 머뭄뒤에 종료 void *t_function(void *data) { char a[100000]; // 자원 점유! static int num = 0; num = *((int *)data); printf("Thread Start\n"); sleep(5); printf("Thread end\n"); return (void*)# } int main() { pthread_t p_thread; int thr_id; int status; int a = 100; printf("Before Thread\n"); thr_id = pthread_create(&p_thread, NULL, t_function, (void *)&a); if (thr_id < 0) { perror("thread create error : "); exit(0); } // 식별번호 p_thread 를 가지는 쓰레드를 detach // 시켜준다. pthread_detach(p_thread); pause(); return 0; }
=> 한개의 쓰레드(메인쓰레드)만 자원 점유!
Before Thread
Thread Start
Thread endhttps://bitsoul.tistory.com/161?category=683199
https://bitsoul.tistory.com/156?category=683199
https://coding-chobo.tistory.com/17
https://inuplace.tistory.com/157
https://bitsoul.tistory.com/172
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=pjfile&logNo=50042459527
728x90'System Programming > Ubuntu Linux' 카테고리의 다른 글
시스템 프로그래밍 실습 13주차 : Synchronization 1 (0) 2021.11.21 시스템 프로그래밍 실습 12주차 : Concurrent Programming (0) 2021.11.15 시스템 프로그래밍 실습 10주차 : Sockets (0) 2021.11.01 Shell 만들기 참고할 것 (0) 2021.10.28 시스템 프로그래밍 실습 9주차 : System V IPC (0) 2021.10.22