Post

(CS)스레드

스레드 (Thread)

스레드란?

  • Light Weight Process 라고도 한다.
  • 하나의 프로세스에 여러개의 스레드를 생성할 수 있다.
  • 스레드들은 동시에 실행이 가능하다.
  • 프로세스 안에 있으므로, 프로세스의 데이터를 모두 접근할 수 있다.

멀티 스레드

멀티스레드

이미지 출처: https://www.fun-coding.org/thread.html

  • Thread는 각기 실행이 가능한 Stack이 존재한다.
  • 소프트웨어 병행작업 처리를 위해 Multi Thread를 사용한다.
  • 멀티 코어의 활용도를 높인다.

스레드의 장점

  • 사용자에 대한 응답성 향상
    • 웹 서버와 같이 사용자의 요청에 따라 빠르게 응답을 줘야하는 상황에서 사용된다.
  • 자원을 공유하여 효율적이다.
    • IPC기법과 같이 프로세스간 자원 공유를 위한 번거로운 작업이 필요없다.
    • 프로세스 안에 있으므로, 프로세스의 데이터에 모두 접근이 가능하다.

스레드의 단점

스레드의 단점

이미지 출처: https://www.fun-coding.org/thread.html

  • 스레드 중 한 스레드만 문제가 있어도, 전체 프로세스가 영향을 받는다.

Thread vs Process

스레드와 프로세스 차이

이미지 출처: https://www.fun-coding.org/thread.html

  • 프로세스는 독립적, 스레드는 프로세스의 서브셋이다.
  • 프로세스는 각각 독립적인 자원을 같는다, 스레드는 프로세스 자원을 공유
  • 프로세스는 자신만의 주소영역을 가진다, 스레드는 주소 영역을 공유
  • 프로세스간의 통신은 IPC기법을 활용해야한다. 스레드는 필요 없다.

동기화 이슈

  • 동기화: 작업들 사이에 실행 시기를 맞추는것
  • 여러 스레드가 동일한 자원에 접근시 동기화 이슈가 발생할 수 있다.
    • 동일 자원을 여러 스레드가 동시에 수정시, 각 스레드의 결과에 영향을 준다.

동기화 해결 방안(Mutual exclusion)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import threading

g_count = 0

def thread_main():
    global g_count
    for i in range(1000000):
        g_count = g_count + 1

threads = []

for i in range(50):
    th = threading.Thread(target=thread_main)
    threads.append(th)

for th in threads:
    th.start()

for th in threads:
    th.join()

print("g_count = ", g_count)
  • range값이 10000정도 일때는 예상하는 값인 500000이 나오지만, 100000이 넘어서는 순간 전혀 예상하지 못한 값이 출력된다.
  • 여러 스레드가 동일한 자원에 접근하여, 작업을하는 도중 동기화로 인한 문제가 발생되어 예상한 값과는 전혀 다른 값이 출력된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import threading

g_count = 0

def thread_main():
    global g_count
    lock.acquire()
    for i in range(100000):
        g_count = g_count + 1
    lock.release()

lock = threading.Lock()

threads = []

for i in range(50):
    th = threading.Thread(target=thread_main)
    threads.append(th)

for th in threads:
    th.start()

for th in threads:
    th.join()

print("g_count = ", g_count)
  • mutual exclusion(상호 배제)을 활용하여, 동기화 이슈를 해결
    • lock.acquire(): 작업이 종료되기 전까지 다른 스레드가 공유 데이터에 접근하는것을 막아준다.
    • lock.release(): lock을 해제
    • 상호배제: 동시 프로그래밍에서 공유 불가능한 자원의 동시 사용을 피하기 위해 사용되는 알고리즘, 임계 구역으로 불리는 코드 영역에 의해 구현된다.
    • 임계 자원을 처리하는 핵심 코드를 임계 구역이라 하며, 이걸 한번에 하나의 작업만을 가능하도록 지정하는것
  • range의 값이 커지더라도 동기화로 인한 이슈가 해결되어, 원하는 결과값을 얻을 수 있게된다.

Mutex와 Semaphore

  • Critical Section(임계 구역)에 대한 접근을 막기 위해 LOCKING 메커니즘이 필요
    • Mutex: 임계구역에 하나의 스레드만 들어갈 수 있다.
    • Semaphore: 임계구역에 여러 스레드가 들어갈 수 있다.
      • counter를 두어 동시에 리소스에 접근 가능한 스레드 수를 제어

교착상태(Deadlock)와 기아상태(Starvation)

교착상태란?

  • 무한 대기 상태: 두개 이상의 작업이 서로 상대방의 작업이 끝나기 만을 기다리고 있기 때문에, 다음 단계로 진행하지 못하는 상태
    • 배치 처리 시스템에서는 일어나지 않는 문제, 프로세스와 스레드 둘 다 이와 같은 상태가 일어날 수 있다.
  • 여러 프로세스가 동일한 자원에 대해 점유를 요청할 때 발생

교착상태 발생 조건

  • 다음 네 가지 조건이 모두 성립될 때, 교착상태 발생 가능성이 있다.
    • 상호배제(Nutual exclusion): 프로세스들이 필요로 하는 자원에 대해 배타적인 통제권을 요구한다.
    • 점유대기(Hold and wait): 프로세스가 할당된 자원을 가진 상태에서 다른 자원을 기다린다.
    • 비선점(No preemption): 프로세스가 어떤 자원의 사용을 끝낼 때까지 그 자원을 뺏을 수 없다.
    • 순환대기(Circular wait): 각 프로세스는 순환적으로 다음 프로세스가 요구하는 자원을 가지고 있다.

교착상태 해결 방법

  • 가장 중요한 핵심은 조건의 일부가 성립이 안되게끔 만들어주는 것이 해결 방법의 가장 중요한 핵심

기아상태란?

  • 특정 프로세스의 우선순위가 낮아서 원하는 자원을 계속 할당 받지 못하는 상태
  • 기아상태는 여러 프로세스가 부족한 자원을 점유하기 위해 경쟁할 때, 특정 프로세스에 영원히 자원이 할당되지 않는 경우를 말한다.

기아상태 해결 방안

  • 우선 순위 변경
  • 프로세스의 우선순위를 수시로 변경하여, 각 프로세스가 높은 우선 순위를 가질 기회를 부여하면 된다.

Reference

스레드와 동기화

This post is licensed under CC BY 4.0 by the author.