여러가지 일들을 동시에 처리 -> multi threading

 

Thread의 개념

  • 프로세스란 프로그램이 실행되고 있는 것 -> 한 부분만 실행
  • 쓰레드를 사용하면 프로그램의 여러부분을 동시에 실행 가능 -> 각각의 부분의 쓰레드라고 함
  • function을 호출해가는 순서, local variable을 저장할 공간이 필요
    • 어느 부분을 하고 있는지를 가리키는 counter와 호출해가는 순서를 기록하는 stack을 각자 개별적으로 보유
  • light-weight process : 쓰레드의 다른 이름 -> 쓰레드들은 프로세스에 있는 메모리 space를 공유해서 사용하기 때문
  • 일반적인 프로세스들은 쓰레드가 1개 밖에 없음

A single-threaded vs. a multi-thread processes

  • single-threaded

    • data : address space에 data를 저장하는 부분
    • file descripter : 파일을 open한 descripter
    • register : cpu상태를 나타내는 register값들
    • stack : function을 어떤식으로 호출해 갔는지
    • code : code의 어떤 부분을 실행하는 thread
  • multi-thread

 

    • 쓰레드가 동시에 실행 중
    • code의 여러부분을 동시에 실행 가능
    • 각각이 cpu의 프로그램 counter를 가지고 있어야하고 stack또한 따로 가지고 있어야 함
    • global한 data와 files는 공유
  • 구체적인 memory map

  • 왼쪽은 일반적인 프로세스의 메모리영역
  • kernel 영역과 user 영역(text, data, Heap, stack이 딱 하나!!!)
  • 오른쪽은 멀티 쓰레드의 메모리영역 -> kernel은 동일
  • data그대로 Heap그대로 / stack이 따로따로 존재 -> 쓰레드마다 각기 다른 부분을 호출하며 수행하기 때문에 각 쓰레드별로 어떤 식으로 호출했는지 stack을 따로 잡아주어야 함

왜 여러개의 프로세스를 사용하지 않고 병렬적인 쓰레드를 사용하는가

  • process
    • fork() : 오버헤드가 큼 - time & memory -> 새로운 프로세스를 생성할 때 매우 많은 시간과 메모리가 필요
    • 각각 독립적인 space를 가지고 있기 때문에 데이터를 주고받기 어려움 -> IPC라는 interprocess comunication mechanism을 사용해야 가능
  • Threads
    • stack영역을 하나 더 추가하는 것이기 때문에 매우 빠름, 하나의 memory space를 공유하기 때문에 메모리 사용량도 적음 
    • data를 공유하기 쉬움(global, static) -> 한 쓰레드가 사용한 것을 다른 쓰레드가 가져다 사용 가능

Multi-threading

  • 쓰레드들이 각각 일정 부분의 일들을 나누어서 처리
  • cpu core들을 여러개 가지고 있는 경우 각각의 cpu에 쓰레드들이 수행하도록 함으로써 병렬로 처리되도록 할 수 있음

  • cpu가 하나만 있는 경우 하나의 cpu에서 여러 쓰레드가 time sharing을 하기 때문에 수행 속도가 빨라지거나 하지 않음
  • 여러 cpu가 있는 경우(core), 각각의 cpu에서 쓰레드를 나누어 수행하는 경우 time sharing을 할 필요가 없어지기 때문에 진정한 병렬처리를 수행 할 수 있게됨 -> 속도가 빨라짐

POSIX threads

  • Pthreads라고 표현
  • Unix계열의 운영체제들에서 multi threading을 하기위한 프로그래밍 API들을 define해놓은 것
  • pthread API
    • 쓰레드 관리 : 생성, 종료 등/ 쓰레드의 속성 결정
    • 데이터 공유할때 어떻게 충돌하지 않도록 공유하는지 -> mutexes, condition variables

  1. pthread_self : 쓰레드의 ID를 가져옴
  2. pthread_equal : 두 쓰레드가 같은 쓰레드인지 비교
  3. pthread_create : 가장 많이 사용, 쓰레드를 생성
  4. pthread_join : 쓰레드가 종료 될 때까지 기다림
  5. pthread_detach : 쓰레드를 Detach
  6. pthread_exit : 쓰레드를 종료시킴

Using Pthreads

  1. 어떤 부분을 thread로 만들 것인가
  2. 함수의 형태로 만듦
  3. pthread_create의 함수의 인자로 넘겨줌
  • libpthread library를 써줘야 컴파일 가능
    • gcc -lpthread -o outputfile threaded_program.c
  • 프로그램 실행 시 생성한 쓰레드들이 동시에 실행 됨 -> 데이터 공간 공유(address space)

pthread_create(3)

 

  • void * (*start_routine) (void *) : 쓰레드를 만들고 싶은 함수의 function pointer를 받아서 argument로 void 포인터를 받고 리턴 값도 동일
  • void *arg : 쓰레드를 수행할 함수에 넘겨줄 argument를 정해줌
  • const pthread_attr_t *attr : 자세히 사용하지 않을 경우 NULL로 세팅
  • pthread_t *thread : 생성하면 handle을 return -> 이것을 가지고 특정한 쓰레드를 지정할 수 있음
  • 성공한 경우 0을, 실패한 경우 -1을 return -> 반드시 확인해야 함!!
    • EAGAIN : 충분한 리소스가 없음 -> ex) 스택을 새로 할당해야 하는데 무한대로 쓰레드를 만들수는 없음(스택이 모자람)

    • pthread_t objects

      • 쓰레드를 지정하기 위해 쓰레드의 ID가 pthread_t 타입으로 return됨

      • 어떤 타입인지 알 필요 없음 -> 내부적으로 구현이 되어있는지 몰라도 됨

      • 보조함수 : Thread IDs

      1. pthread_self : pthread_t 타입, 자기자신의 thread ID를 리턴

      2. pthread_equal : 두 쓰레드가 같은 쓰레드인지 비교

    • Function started by pthread_create(3)

    • argument로 void pointer를 받고 리턴값으로 void pointer로 넘겨줌 -> 어떠한 데이터에 대한 포인터도 넘겨줄 수 있다는 의미 -> type casting을 하여 사용

    • 리턴값 또한 사용할 때 type casting을 하여 사용

    • 예제

     

    1. pthread.h를 include
    2. pthread_t의 핸들을 선언
    3. attribute는 NULL, 쓰레드는 snow라는 함수 수행, data(string)
    4. (char *)data : type casting을 함
    5. snow가 수행되는 동안 main 쓰레드도 수행 됨
    • fork()와 비교

    • 완전히 동일한 프로세스가 생성됨 -> 오래 걸림

    • 메인 쓰레드가 수행되고 있는 상태에서 새로운 쓰레드를 만들면 Stack만 새로 만들어지고 나머지 부분은 공통으로 사용
    • 각각의 thread를 위한 스택이 존재

    쓰레드의 종료

     

    1. return으로 종료 됨, thread를 pthread_exit라는 함수를 불러서 명시적으로 종료시킴
    2. pthread_exit() : 종료되기를 기다리고 있는 어떤 쓰레드에게 retval값을 넘겨줄 수 있음 -> pthread_exit()를 하게 되면 프로그램 자체가 종료 되는 것이 아니라 다른 쓰레드들은 수행중임
    3. exit()는 프로세스 자체가 종료되므로 모든 쓰레드가 종료됨
    4. pthread_cancle()
    • 종료하면서 넘겨주는 return값을 기다리는 함수 : pthread_join(3)

    • thread가 종료되기를 기다림
    • **retval : retrun값을 가져옴 -> 가져올 필요가 없다면 NULL로 설정
    • 여러개가 종료되기를 기다리기 위해서는 각 쓰레드마다 join을 해야함
    • 예제

    1. main thread가 수행되고 있다가 func이라는 함수를 수행하는 쓰레드가 생성됨
    2. pthread_join이라는 함수를 부름 -> mythread가 종료될 때 까지 기다림
    3. func가 만약 (void *)42를 return했다면 그 값을 i에 받아서 사용할 수 있음
    • pthread_detach(3)

     

    • 한 쓰레드가 종료했을 때 exit값을 받아가야 종료된 쓰레드에 관련된 자원들이 릴리즈 됨
    • 그러나 쓰레드를 종료하는 것을 기다리지 않겠다고 선언하는 함수가 pthread_detach라는 함수
    • thread에 종료될 thread를 넣으면 이 thread가 종료 될 때 기다리지 않고 바로 종료한다는 뜻

    1. 여러 쓰레드 생성 -> create
    2. 각 쓰레드가 종료 될 때마다 기다려서 return값을 가져옴

    1. 각 쓰레드를 기다리지 않음 -> pthread_detach()

     

     

     

     

     

     

    + Recent posts