Operating System
Threads
- Execution units in a process → 서로 다른 threads는 같은 address space를 공유한다. 같은 process에서의 실행 유닛이기 때문이다.
- Each thread runs in the context of the process and shares the same code and global data
- Easier to share data between multiple threads than processes → fork()를 통해 multi-process를 하는 것 보다는 multi-tread를 하는 것이 더 쉽고 빠르다.
- Typically, more efficient than processes
Virtual Address Space
Process
+ 서로 다른 processes들은 threads와 달리 address space를 공유하지 않습니다.
Thread
+ 같은 프로세스에 위치한 쓰레드는 같은 가상 공간을 공유함을 알 수 있습니다.
+ thread마다 stack이 있어야합니다.
+ stack외의 다른 데이터들은 공유합니다. 즉, Run-time heap이나 code들을 공유합니다.
Thread Creation
- int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg)
pthread_t thread: thread identifier
const pthread_attr_t: thread attribution (NULL for default)
void *(*start) (void*): thread function
void *arg: argument for thread function
Return value: 0 if success, otherwise error code
+ thread가 새로 만들어지면 새로 만들어진 thread에 대한 program counter가 새로 만들어집니다. 하지만 pc를 가르키는 register인 rip register가 2개가 되는것이 아니라, thread간의 context switch에서 pc가 되는 값이 따로 생성된다는 의미입니다.
Thread Identifiers
- Process ID
- getpid()
- Thread IDs
- Thread ID returned by pthread_create() and pthread_self()
- Used to refer to the thread in subsequent calls to other pthreads functions → 다른 pthread함수를 사용할 때 사용되는 descriptor입니다.
- Thread IDs should be considered opaque
- Thread ID는 process안에서 유일한 값입니다. 하지만 system에서는 유일한 값이 될 수 없습니다.
- Thread ID returned by gettid()
- Linux-specific kernel-level thread ID
- System에서 유일한 Thread ID로 운영체제가 관리하는 Thread ID입니다.
- Thread ID returned by pthread_create() and pthread_self()
Thread Attributes
- pthread_attr_t
- Initialization
- int pthread_attr_init(pthread_attr_t *tattr)
- Detach state
- PTHREAD_CREATE_JOINABLE: Completion status and thread ID are preserved after the thread exits
- pthread_attr_setdetachstate()
- Scope
- PTHREAD_SCOPE_SYSTEM: The thread competes for resoirces with all other threads in all processes on the system → OS스케쥴러의 자원을 경쟁하는 쓰레드의 범위를 설정합니다.
- pthread_attr_setscope()
- Inherit scheduler
- PTHREAD_INHERIT_SCHED: New thread inherits scheduling attributes from the the creating thread → thread의 상속 유뮤를 설정합니다.
- Scheduling policy
- SCHED_OTHER: New thread uses the standard scheduling policy
- pthread_attr_setschedpolicy()
- Scheduling priority
- 0: Priority is not used in scheduling decisions
- pthread_attr_setschedparam()
- Guard size
- Page size (4KB): Stack overflow protection
- pthread_attr_setguardsize()
- Stack size
- 8MB: New thread has 8MB stack size
- pthread_attr_setstacksize()
- Initialization
Resource Usage Limits
- ulimit command
- set or get the resource usage limits of the shell and any processes → shell이나 shel의 자식 프로세스들의 attr를 확인할 수 있는 command입니다. processes들의 제한들을 확인한다는 의미에서 ulimit입니다.
- > ulimit -a
- System resource limits
- /proc/sys/kernel/thread-max
- /proc/sys/fs/file-max
- ...
- shell말고 전체 system의 attr를 확인할 수 있습니다.
Terminating Threads
- void pthread_exit(void *retval)
- Terminates calling thread
- Returns a value via retval that is available to another thread in the same process that call pthread_join() → 같은 프로세스 내의 다른 thread에서 pthread_join()을 통해 받아올 수 있는 return value를 *retval을 통해 보낼 수 있습니다.
- int pthread_cancel(pthread_t thread)
- Sends a cancellation request to a thread → Tread ID를 통해 해당 thread를 종료할 수 있습니다.
Joining Threads
- int pthread_join(pthread_t thread, void **value_ptr)
- Blocks the caller until the thread you specify has terminated and reaps any memory resources held by the terminated thread → Thread ID를 통해 특정한 thread가 종료할 때까지 기다립니다. void **value_ptr을 통해 해당 thread에서 return한 값을 얻어올 수 있습니다.
- Return value: 0 if success, otherwise error code
Detaching Threads
- Joinable threads (default)
- Can be reaped and killed by other threads
- Memory resources are not freed until it is reaped by another thread → 기본적인 thread는 joinable thread로 pthread_join()을 통해 reap을 할 수 있고, kill도 가능합니다.
- Detached threads
- Cannot be reaped and killed by other threads
- Memory resources are freed automatically when it terminates → thread가 detach가 되면 다른 thread에 의해 reap이나 kill이 될 수 없고, 해당 thread가 종료되면 자동으로 reap이 됩니다.
- int pthread_detach(pthread_t thread)
Dummy Example
void *thread_routine(void *arg)
{
pid_t my_pid;
pthread_t my_tid;
my_pid = getpid();
my_tid = pthread_self();
printf("New thread: pid %d, tid &lu\n", my_pid. my_tid);
return arg;
}
int main()
{
pthread_t thread_id, my_tid;
pid_t my_pid;
void *thread_result;
int status;
my_pid = getpid();
my_tid = gettid();
printf("Main thread: pid %d, tid %lu\n", my_pid, my_tid);
status = pthread_create(&thread_id, NULL, thread_routine, NULL);
if(status != 0){
perror("pthread_create");
exit(1);
}
status = pthread_join(thread_id, &thread_result);
if(status != 0){
perror("pthread_join");
exit(1);
}
return 0;
}
result
+ pid, 즉 같은 process를 공유하지만, tid, thread는 다름을 알 수 있습니다. thread가 생성되는 것은 fork()와 달리 다른 process가 생기는 것이 아닌 같은 process안에서 새로운 실행 유닛을 만드는 것입니다.
Passing Arguments
/* arguments */
typedef struct{
int i;
char str[MAX_STR];
} my_arg;
/* return value */
typedef struct{
int i;
char c;
} my_ret;
void *thread_routine(void *arg)
{
my_arg *targ = (my_arg *)arg;
my_ret *ret = malloc(sizeof(my_ret));
if(strlen(targ->str > targ->i){
ret->i = targ->i;
ret->c = targ->str[ret->i];
}
else
ret->i = -1;
return ret;
}
int main(void)
{
pthread_t thread_id;
int status;
my_arg arg;
my_ret *ret;
arg.i = rand() % MAX_STR;
fgets(arg.str, MAX_STR, stdin);
status = pthread_create(&thread_id, NULL, thread_routine, &arg);
if(status != 0){
perror("create");
exit(1);
}
status = pthread_join(thread_id, (void **)&ret);
if(status != 0){
perror("join");
exit(1);
}
if(ret->i > -1)
printf("%dth character of %s in %c\n", ret->i, arg.str, ret->c);
else
printf("out of range\n");
return 0;
}
result
'[학교 수업] > [학교 수업] 시스템 프로그래밍' 카테고리의 다른 글
[시스템 프로그래밍] Miscellaneous Thread Topics (1) | 2024.11.12 |
---|---|
[시스템 프로그래밍] Thread Synchronization (0) | 2024.10.31 |
[시스템 프로그래밍] Message Queue (3) | 2024.10.17 |
[시스템 프로그래밍] Pipes (3) | 2024.10.15 |
[시스템 프로그래밍] Inter-Process Communication (3) | 2024.10.11 |