thread ?

About_work·2024년 7월 23일
0

process, thread

목록 보기
23/23

0. 들어가기 전에

1. 프로세스와 스레드의 기본 개념

프로세스(Process):

  • 프로그램이 실행 중인 상태를 말합니다.
  • 각 프로세스는 독립적인 메모리 공간을 가지고 있음
  • 운영체제는 각 프로세스에 고유한 주소 공간을 할당

스레드(Thread):

  • 스레드는 프로세스 내에서 실행되는 작은 단위
  • 여러 스레드가 하나의 프로세스 내에서 실행될 수 있습니다.
  • 스레드는 프로세스의 자원을 공유합니다.

1.2. 힙(Heap)과 스택(Stack)의 차이점

힙(Heap):

  • 힙은 동적 메모리 할당을 위해 사용되는 영역
  • 런타임에 메모리를 할당하고 해제할 수 있음
  • 힙 메모리는 전역적이며, 프로세스 내 모든 스레드가 접근할 수 있습니다.
  • 예를 들어, 동적 할당(예: malloc 또는 new 연산자)을 통해 생성된 객체들은 힙에 저장됩니다.

스택(Stack):

  • 스택은 함수 호출과 관련된 메모리 할당을 위해 사용
  • 각 함수 호출 시마다 스택 프레임이 생성되고, 함수가 종료되면 해당 스택 프레임이 제거
  • 스택 메모리는 각 스레드마다 개별적으로 할당
  • 즉, 스레드마다 고유한 스택 공간이 있어서 다른 스레드의 스택에 접근할 수 없습니다.

1.3. 스레드가 힙과 스택을 다루는 방식

힙의 공유:

  • 모든 스레드는 힙 메모리를 공유
  • 따라서 한 스레드에서 힙에 할당된 메모리를 다른 스레드가 접근하고 수정할 수 있음
  • 이러한 특성 때문에 동기화 문제(예: 경쟁 상태, 데드락 등)가 발생할 수 있음
  • 따라서 멀티스레드 환경에서 힙 메모리에 접근할 때는 동기화 기법(예: 뮤텍스, 세마포어 등)을 사용하여 데이터 무결성을 유지해야 함

스택의 독립성:

  • 각 스레드는 독립적인 스택 공간을 갖습니다.
    • 스택에는 함수의 지역 변수, 함수 호출 시 전달된 인자, 리턴 주소 등이 저장
  • 하나의 스레드가 다른 스레드의 스택에 접근할 수 없기 때문에, 스택은 스레드 안전(Thread-safe)한 공간
  • 예를 들어, 스레드 A의 함수 호출로 인해 생성된 지역 변수는 오직 스레드 A만 접근할 수 있으며, 스레드 B는 스레드 A의 스택에 접근할 수 없습니다.

1.4. 힙과 스택의 구조 및 사용 사례

힙 구조 및 사용 사례:

  • 구조:
    • 힙은 자유롭게 사용 가능한 메모리 블록으로 구성
    • 메모리 할당 요청이 있을 때, 적절한 크기의 블록이 할당됨
  • 사용 사례:
    • 동적 데이터 구조
    • 런타임에 크기가 결정되는 데이터 저장.

스택 구조 및 사용 사례:

  • 구조:
    • 스택은 LIFO(Last In First Out) 방식으로 데이터가 저장
    • 함수 호출 시마다 스택 프레임이 쌓이고, 함수가 종료되면 해당 프레임이 제거
  • 사용 사례:
    • 함수 호출 시 지역 변수 및 매개변수 저장, 함수 리턴 주소 저장, 함수 호출 체인 관리.

2. 심화 설명

  • 멀티스레드 프로그래밍에서 각 스레드는 프로세스 내의 4가지 메모리 공간 중 코드(code)와 데이터(data) 영역, heap 영역을 공유하고,
  • 각 스레드는 별도의 레지스터를 갖는다는 점을 구체적으로 설명드리겠습니다.

2.1. 프로세스의 4가지 메모리 공간

  1. 힙 영역 (Heap Segment):
    • 동적 메모리 할당을 위한 영역입니다. 모든 스레드가 공유합니다.
  2. 스택 영역 (Stack Segment):
    • 함수 호출과 관련된 지역 변수와 매개변수가 저장되는 영역입니다. 각 스레드는 독립적인 스택을 가집니다.

2.2. 각 스레드는 별도의 레지스터를 갖는다

레지스터:

  • 레지스터는 CPU 내부의 고속 메모리로, 명령어 실행에 필요한 데이터를 임시로 저장하는 공간
  • 각 스레드는 독립적인 레지스터 집합을 가지며,
    • 프로그램 카운터(PC), 스택 포인터(SP), 베이스 포인터(BP) 등이 포함

2.3. Python 예제

  • 다음은 Python의 threading 모듈을 사용하여 멀티스레드 프로그램을 작성한 예제
  • 이 예제를 통해 스레드들이 코드와 데이터를 공유하는 방식과 독립적인 스택을 사용하는 방식을 이해할 수 있습니다.
import threading
import time

# 전역 변수 (Data Segment에 저장됨)
shared_data = 0

# 스레드가 실행할 함수 (Code Segment에 저장됨)
def thread_function(name):
    global shared_data
    for i in range(5):
        time.sleep(1)
        # 전역 변수에 접근하고 수정 (Data Segment 공유)
        shared_data += 1
        print(f"Thread {name}: shared_data = {shared_data}")

# 스레드 생성
thread1 = threading.Thread(target=thread_function, args=("A",))
thread2 = threading.Thread(target=thread_function, args=("B",))

# 스레드 시작
thread1.start()
thread2.start()

# 메인 스레드가 다른 스레드들이 끝날 때까지 기다림
thread1.join()
thread2.join()

print("Final shared_data:", shared_data)

2.3.1. 코드 설명

  1. 코드 영역 (Code Segment):

    • 정의: 프로그램의 실행 코드를 포함합니다. 모든 스레드가 공유합니다.
    • thread_function 함수는 코드 영역에 저장됩니다.
    • 이 함수는 두 스레드(thread1thread2)에서 동시에 실행
  2. 데이터 영역 (Data Segment):

    • 정의: 초기화된 전역 변수와 정적 변수가 저장되는 영역입니다. 모든 스레드가 공유
    • shared_data는 전역 변수로, 데이터 영역에 저장됩니다.
      • 두 스레드는 이 변수를 공유하며, 각 스레드가 값을 수정할 수 있습니다.
    • 두 스레드는 shared_data를 공유하므로, 하나의 스레드에서 이 값을 수정하면 다른 스레드도 수정된 값을 볼 수 있습니다.
  3. 힙 영역 (Heap Segment):

    • 이 예제에서는 힙 메모리를 직접 사용하지 않지만, 만약 스레드들이 동적 데이터 구조를 할당하면 힙 영역을 공유하게 됩니다.
  4. 스택 영역 (Stack Segment):

    • 각 스레드는 독립적인 스택을 가집니다.
    • thread_function 함수 내에서 선언된 지역 변수와 매개변수(name 등)는 각 스레드의 스택에 저장
    • 예를 들어, name 매개변수는 thread1 스레드에서는 "A"로, thread2 스레드에서는 "B"로 독립적으로 저장됩니다.

2.4. 스레드의 레지스터

  • 각 스레드는 독립적인 레지스터 집합을 가집니다. 이는 다음과 같은 이유로 중요합니다:

  • 프로그램 카운터 (PC):

    • 각 스레드는 현재 실행 중인 명령어의 주소를 독립적으로 유지
    • 예를 들어, thread1thread2thread_function 내에서 다른 명령어를 실행하고 있을 수 있습니다.
  • 스택 포인터 (SP)베이스 포인터 (BP):

    • 각 스레드는 고유의 스택을 가지므로, 스택 포인터와 베이스 포인터도 독립적입니다.
    • 이는 각 스레드가 함수 호출과 관련된 데이터를 독립적으로 관리할 수 있게 합니다.
  • 이 예제에서는 두 스레드가 shared_data를 공유하여 값을 수정하는 것을 볼 수 있습니다.

  • 이는 데이터 영역을 공유하는 스레드의 특성을 보여줍니다.

  • 각 스레드가 name 매개변수를 독립적으로 가지는 것은 스택을 독립적으로 사용하는 것을 보여줍니다.

profile
새로운 것이 들어오면 이미 있는 것과 충돌을 시도하라.

0개의 댓글