이 포스트는 Udacity - Introduction to Operating Systems를 강의 내용을 필기 형식으로 작성 했습니다.
What is Pthread ?
POSIX 스레드(POSIX Threads, 약어: PThread)는 병렬적으로 작동하는 소프트웨어의 작성을 위해서 제공되는 표준 API다.
Thread struct
pthread_t aThread; // type of Threadpthread Attributes (pthread_attr_t)
- pthread_create 안에 명시 하여 pthread 설정하도록 함
- pthread_create 안에 NULL로 보낼시 default 값으로 설정 됨
- 새로운 쓰레드에 특징을 명시 한다
특징들:
- stack size
- inheritance
- joinable
- scheduling policy
- priority
- system / process scope
// initialize pthread attribute structure
int pthread_attr_init(pthread_attr_t *attr);
// destroy and free pthread attribute structure from memory
int pthread_attr_destroy(pthread_attr_t *attr);
// set or get value.
//ex) int pthread_attr_{set/get}{attribute}
int pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// detach 관련 설정
int pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
// scope 관련 설정, resource sharing scope 를 system scope로 변경
// (system의 모든 thread와 자원을 균등하게 사용 하겠다는 설정)Thread createtion
int pthread_create (pthread_t *thread, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg));
//return 값은 create 함수 실행 결과Thread Join
int pthread_join(pthread_t thread, void **status);
// void **status <- 연관된 Thread 상태 값 반환
// return 값은 join 함수 실행 결과Compiling PThread
1) include header file in main file.
#include <pthread.h>2) Compile source with -lpthread or pthread
gcc -o main main.c -lpthread
gcc -o main main.c -pthreadDetaching PThread
Default: joinable threads
- Detach 하지 않고 부모 thread 가 자식thread 보다 먼저 exit 하면 자식thread는 좀비가 됨.
- Detach 시키면 부모thread 가 exit 해도 자식thread는 계속 동작
- 한번 Detach되면 다시 join할 수 없음
int pthread_detach();
pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACH);
// ...
pthread_create(...., attr, ....);
void phread_exit();PThread Mutexes
“to solve mutual exclusion problems among concurrent trheads”
mutex 구조체
pthread_mutex_t aMutex; // mutex type
int pthread_mutex_lock(pthread_mutex_t *mutex); // explicit lock
int pthread_mutex_unlock(pthread_mutex_t *mutex); // explicit unlock사용 예)
list<int> my_list;
pthread_mutex_t m;
void safe_insert(int i) {
pthread_mutex_lock(m);
my_list.insert(i);
pthread_mutex_unlock(m);
}other mutex operation
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
// mutex attribute : 프로세스 사이에서 공유될때 mutex 행동 설정
int pthread_mutex_trylock(pthread_mutex_t *mutex);
// mutex lock 가능한지 확인 하는 기능
int pthread_mutex_destroy(pthread_mutex_t *mutex);
// mutex 삭제
... many othrers ...pthread condition variable
- condition
ex) pthread_cond_t aCond; // type of cond variable
- wait
: 기다리다가 mutex가 release되면 mutex획득
ex) int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
- signal
: wait 중인 쓰레드에게 신호 보냄
ex) int pthread_cond_signal(pthread_cond_t *cond);
- broadcast
: 전체 쓰레드에 신호 보냄
ex) int pthread_cond_broadcast(pthread_cond_t *cond);Other condition variable operations
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
// attributes -- e.g., if it's shared
// attr = null // default behavior
// further specifiy behavior
int pthread_cond_destroy(pthread_cond_t *cond);
// condition variabl 제거 Create pthread without parameter
/* PThread Creation Quiz 1 */
#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 4
void *hello (void *arg) { /* thread main */
printf("Hello Thread\n");
return 0;
}
int main (void) {
int i;
pthread_t tid[NUM_THREADS];
for (i = 0; i < NUM_THREADS; i++) { /* create/fork threads */
pthread_create(&tid[i], NULL, hello, NULL); // Null <- without parameter
}
for (i = 0; i < NUM_THREADS; i++) { /* wait/join threads */
pthread_join(tid[i], NULL);
}
return 0;
}
/*
output result:
Hello Thread
Hello Thread
Hello Thread
Hello Thread
*/Create pthread with parameter
/* PThread Creation Quiz 3 */
#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 4
void *threadFunc(void *pArg) { /* thread main */
int myNum = *((int*)pArg);
printf("Thread number %d\n", myNum);
return 0;
}
int main(void) {
int i;
int tNum[NUM_THREADS];
pthread_t tid[NUM_THREADS]; // pthread_t 생성
for(i = 0; i < NUM_THREADS; i++) { /* create/fork threads */
tNum[i] = i; // paramter 넘기기
pthread_create(&tid[i], NULL, threadFunc, &tNum[i]); // <-- &tNum[i] is parameter
// pthread create
}
for(i = 0; i < NUM_THREADS; i++) { /* wait/join threads */
pthread_join(tid[i], NULL);
}
return 0;
}
/*
output result:
Thread number 0
Thread number 1
Thread number 2
Thread number 3
*/Producer & Consumer
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define BUF_SIZE 3 /* Size of shared buffer */
int buffer[BUF_SIZE]; /* shared buffer */
int add = 0; /* place to add next element */
int rem = 0; /* place to remove next element */
int num = 0; /* number elements in buffer */
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; /* mutex lock for buffer */
pthread_cond_t c_cons = PTHREAD_COND_INITIALIZER; /* consumer waits on this cond var */
pthread_cond_t c_prod = PTHREAD_COND_INITIALIZER; /* producer waits on this cond var */
void *producer (void *param);
void *consumer (void *param);
int main(int argc, char *argv[]) {
pthread_t tid1, tid2; /* thread identifiers */
int i;
/* create the threads; may be any number, in general */
if(pthread_create(&tid1, NULL, producer, NULL) != 0) {
fprintf(stderr, "Unable to create producer thread\n");
exit(1);
}
if(pthread_create(&tid2, NULL, consumer, NULL) != 0) {
fprintf(stderr, "Unable to create consumer thread\n");
exit(1);
}
/* wait for created thread to exit */
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("Parent quiting\n");
return 0;
}
/* Produce value(s) */
void *producer(void *param) {
int i;
for (i=1; i<=20; i++) {
/* Insert into buffer */
pthread_mutex_lock (&m);
if (num > BUF_SIZE) {
exit(1); /* overflow */
}
while (num == BUF_SIZE) { /* block if buffer is full */
pthread_cond_wait (&c_prod, &m);
}
/* if executing here, buffer not full so add element */
buffer[add] = i;
add = (add+1) % BUF_SIZE;
num++;
pthread_mutex_unlock (&m);
pthread_cond_signal (&c_cons);
printf ("producer: inserted %d\n", i);
fflush (stdout);
}
printf("producer quiting\n");
fflush(stdout);
return 0;
}
/* Consume value(s); Note the consumer never terminates */
void *consumer(void *param) {
int i;
while(1) {
pthread_mutex_lock (&m);
if (num < 0) {
exit(1);
} /* underflow */
while (num == 0) { /* block if buffer empty */
pthread_cond_wait (&c_cons, &m);
}
/* if executing here, buffer not empty so remove element */
i = buffer[rem];
rem = (rem+1) % BUF_SIZE;
num--;
pthread_mutex_unlock (&m);
pthread_cond_signal (&c_prod);
printf ("Consume value %d\n", i); fflush(stdout);
}
return 0;
}
/*
output result:
producer: inserted 1
Consume value 1
producer: inserted 2
Consume value 2
producer: inserted 3
Consume value 3
...
...
producer: inserted 18
Consume value 18
producer: inserted 19
Consume value 19
producer: inserted 20
Consume value 20
producer quiting
프로세스는 종료 되지 않은 상태로 유지 (이유: consumer가 무한 루프이고 main에 join되어 있기 때문)
*/