ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Thread ( + pthread)
    컴퓨터 구조 2021. 1. 23. 00:28

    Process

    "메모리에 적재되어 실행중인 프로그램"

    • 사용자의 프로그램이 OS에 의해 메모리 공간을 할당받아 실행 중인 것을 말한다.

    • 프로세스는 프로그램에 사용되는 데이터 메모리자원 그리고 thread로 구성된다.

    • 하드디스크의 프로그램을 실행하면, 프로그램 실행을 위해 메모리 할당이 이루어진다. 할당된 메모리 공간에 바이너리 코드가 올라가며 프로세스가 실행된다.

     

    Thread

    프로세스는 스레드라고 하는 실행 유닛으로 구성되어 있다. 모든 프로세스에서 한 개 이상의 스레드가 존재하고 스레드가 작업을 수행한다. 

    스레드는 서로 code, data, heap영역을 공유하고 stack영역을 별도로 사용한다. 따라서, 별도의 process를 실행시키는 것 보다 데이터 공유를 쉽게 할 수 있고 효율적이다.

     

     

    Pthread

    c언어에서 thread를 구현해주는 libraray pthread를 통해 간단한 실습을 진행해보자.

    리눅스 환경에서 gcc를 이용해 컴파일해야 하는데, Online C Compiler에서 간단하게 구현해볼 수 있다.

     

    pthread_create 

    pthread_create()함수는 프로세스에서 새로운 스레드를 생성한다. 유닉스 프로세스는 별도의 스레드를 만들어 주지 않는 한 싱글 스레드 프로세스이다. pthread_creat()함수를 이용해 스레드를 생성해, 멀티스레드 프로세스를 만들어보자.

    int pthread_create (pthread_t *restrict tidp, const pthread_attr_t *restrict attr,
                                   void *(*start_rtn)(void*), void *restrict arg);

    pthread_t *restrict tidp

    스레드가 성공적으로 생성되었느니 확인 & 스레드 식별

    pthread_join을 이용해 메모리 자원을 해제할 때 사용되기도 한다.

     

    const pthread_attr_t *restrict attr

    스레드의 특성을 지정한다. NULL을 입력하면, default 특성이 적용된다.

     

    void *(*start_rtn)(void*)

    스레드를 생성해 실행할 스레드 함수이다.

     

    void *restrict arg

    위의 스레드 함수의 매개변수로 넘겨지는 매개변수이다.

     

     

    pthread_join

    thread id를 인자로 받아 스레드의 종료를 기다린다. 스레드는 종료되더라도 메모리 자원이 자동으로 해제되지 않는데, pthread_join이 할당된 자원을 해제시켜 메모리 누수를 방지한다.

    int pthread_join (pthread_t *tidp, void **thread_return);

    pthread_t *tidp

    종료를 기다릴 thread의 id

     

    void **thread_return

    스레드 종료시에 반환되는 값을 저장한다.

     

     

    what is the meaning of restrict in the function signature? stackoverflow

     

    Code [Online C Compiler]- ref

    #include <pthread.h>
    //pthread를 사용하기 위해서는 먼저 #include <pthread.h>로 헤더를 추가해주어야 한다.
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
     
    // 쓰레드 함수
    void *t_function(void *data)
    {
        pid_t     pid = getpid();	    //get process id
        pthread_t tid = pthread_self(); //get thread id
     
        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("end\n");
     
        return 0;
    }
    reference : Happy programmer [https://bitsoul.tistory.com/157?category=683199]

     

    출력을 확인해보면, pid는 모두 같고 main thread, thread_1 그리고 thread_2가 각자의 고유한 tid를 가지고 번갈아가며 실행되었음을 확인할 수 있다.

    다중 스레드가 실행되었음을 확인할 수 있다.

     

     

    스레드 동기화

     

    두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스라고 한다. 

    그런데 이렇게 하나의 프로세스에서 여러 스레드가 실행될 때, 동시성에 대한 문제가 생긴다. 스레드는 stack segment를 제외한 영역들을 서로 공유한다. 이 영역에 있는 값들을 읽고 쓸때, 하나의 스레드가 값을 변경하고, 그 자리의 값을 다른 스레드가 읽으면, 원하는 값과 다른 값이 읽히는 것이다.

    이렇게 멀티 스레드 환경에서 발생하는 다양한 문제들을 해결하기 위해 스레드 동기화를 하게 된다.

     

    스레드 동기화에는 네가지 방법이 있다. 이들 중, mutex에 대해 조금 더 자세히 알아보자.

    • critical section공유 영역을 사용할 때, 하나의 스레드의 접근만 허용한다. 하나의 프로세스에 속한 스레드에만 사용 가능하다.
    • mutexcritical section과 동일하게 공유영역에 하나의 스레드의 접근만을 허용한다. mutex는 서로 다른 프로세스에 속한 스레드에도 사용 가능하다.
    • event특정 사건이 발생했음을 다른 스레드들에게 알린다.
    • semaphore한정된 자원을 여러 스레드가 사용하려 할 때 접근을 제한한다.
    프로세스 간 통신 IPC

    프로세스 간에 데이터를 주고 받는 상황이 존재한다. 데이터를 주고 받는 방법들 중 하나로, 공유 메모리 모델이 존재하는데, 프로세스가 다른 프로세스들과 공유할 수 있는 공간을 별도로 할당해준다. 이 메모리 영역에는 다른 프로세스들이 접근할 수 있게 된다.

    이러한 상황에서 mutex를 이용한 스레드 동기화를 사용해야 한다. mutex는 동작속도가 느리기 때문에, 프로세스간에 위와 같이 메모리를 공유하는 상황이 없다면 critical section을 사용하는 것을 추천한다.

     

     

    Mutex를 이용한 스레드 동기화 예제 블로그

     

     

    틀린 부분이 있을 수 있습니다. 감사합니다.

     

     

    reference

    - os-process

    - thread

    - 스레드 동기화

    - critical section vs mutex

    - IPC

    - pthread_create

    - pthread_join

     

     

    '컴퓨터 구조' 카테고리의 다른 글

    운영체제 - CPU 가상화(스케줄링 & 공유자원 관리)  (0) 2021.05.07
    Pintos - Virtual Memory  (0) 2021.03.03
    pointer & memory segment  (0) 2021.01.18
    B-Tree - 삭제  (0) 2021.01.18
    B-Tree - 삽입  (0) 2021.01.13
Designed by Tistory.