Загружаем каталог…
Загружаем каталог…
Thread 는 프로그램 안에서 코드를 실행하는 하나의 실행 흐름 이다. 하나의 프로그램에서도 여러 Thread를 사용하면 여러 작업을 나누어 처리할 수 있다. 한 줄 요약: Thread는 프로그램 내부에서 독립적으로 코드를 실행할 수 있는 하나의 작업 흐름이다. Thread란? 일반적인 프로그램은 먼저 하나의 Thread에서 실행된다. Main Thread Start() ↓ Update() ↓ Attack() ↓ Move() 코드가 하나의 실행 흐름을 따라 순서대로 실행되는 것이다. 하지만 Thread를 추가하면 Main Thread ├─ 게임 로직 ├─ 입력 처리 └─ 렌더링 관련 작업 Worker Thread └─ 별도의 계산 작업 처럼 서로 다른 실행 흐름을 만들 수 있다. .NET의 Thread 클래스는 Thread를 생성하고 제어하는 역할을 한다. Thread 만들기 Thread를 사용하려면 using System.Threading; 을 추가한다. 간단한 Thread는 다음처럼 만들 수 있다. void Work() { Console.WriteLine("작업 실행"); } Thread thread = new Thread(Work); 하지만 이 상태에서는 아직 실행되지 않는다. 실행하려면 thread.Start(); 를 호출해야 한다. 전체 코드는 다음과 같다. void Work() { Console.WriteLine("작업 실행"); } Thread thread = new Thread(Work); thread.Start(); Thread 생성자는 실행할 메서드를 나타내는 ThreadStart Delegate를 받을 수 있다. Main Thread와 Worker Thread 예를 들어 void Work() { for (int i = 0; i < 5; i++) { Console.WriteLine($"Worker : {i}"); } } Thread thread = new Thread(Work); thread.Start(); for (int i = 0; i < 5; i++) { Console.WriteLine($"Main : {i}"); } 를 실행하면 결과가 반드시 Worker 0 Worker 1 Worker 2 Main 0 Main 1 ... 처럼 일정하게 나오지는 않는다. 상황에 따라 Main 0 Worker 0 Worker 1 Main 1 Worker 2 ... 처럼 섞여서 실행될 수 있다. 즉 여러 Thread의 실행 순서는 항상 동일하다고 보장할 수 없다. Thread.Sleep() 현재 실행 중인 Thread를 일정 시간 동안 멈출 수 있다. Thread.Sleep(1000); 1000 은 밀리초이므로 1000ms = 1초 이다. 예를 들면 void Work() { Console.WriteLine("시작"); Thread.Sleep(1000); Console.WriteLine("1초 후"); } 이 된다. 중요한 점은 Thread.Sleep() 은 해당 Thread 자체를 멈춘다. 는 것이다. Unity에서 Sleep을 주의해야 하는 이유 예를 들어 Unity의 Main Thread에서 Thread.Sleep(3000); 을 실행하면 Main Thread가 3초 동안 멈춘다. 그러면 Update 입력 처리 게임 로직 화면 처리 등도 같이 멈출 수 있다. 즉 게임이 멈춘 것처럼 보일 수 있다. 따라서 Unity의 시간 지연이 목적이라면 보통 yield return new WaitForSeconds(1f); 같은 Coroutine 방식이 더 적절하다. Thread.Join() Join() 은 다른 Thread의 작업이 끝날 때까지 현재 Thread를 기다리게 하는 메서드 이다. 예를 들어 Thread thread = new Thread(Work); thread.Start(); thread.Join(); Console.WriteLine("작업 완료"); 라고 하면 Worker Thread 시작 ↓ Work 실행 ↓ Work 종료 ↓ Join 종료 ↓ 작업 완료 출력 순서가 된다. Thread.Join() 은 대상 Thread가 종료될 때까지 호출한 Thread를 Block 한다. Join 사용 예제 void Work() { Thread.Sleep(1000); Console.WriteLine("Worker 완료"); } Thread thread = new Thread(Work); thread.Start(); Console.WriteLine("기다리는 중"); thread.Join(); Console.WriteLine("모든 작업 완료"); 결과는 기다리는 중 약 1초 Worker 완료 모든 작업 완료 와 같은 흐름이 된다. Thread와 Delegate 앞에서 공부한 Delegate와도 연결된다. Thread 생성자는 실행할 메서드를 전달받는다. void Work() { Console.WriteLine("작업"); } Thread thread = new Thread(Work); 여기서 Work 라는 메서드를 Thread에게 전달한다. 람다식으로도 작성할 수 있다. Thread thread = new Thread(() => { Console.WriteLine("작업 실행"); }); thread.Start(); 즉 지금까지 배운 Delegate ↓ Lambda ↓ Thread에 실행할 코드 전달 이라는 연결도 가능하다. 여러 Thread에서 같은 데이터 사용 Thread에서 가장 중요한 문제 중 하나다. 예를 들어 int count = 0; 을 두 Thread가 동시에 수정한다고 하자. void Add() { for (int i = 0; i < 10000; i++) { count++; } } 그리고 Thread thread1 = new Thread(Add); Thread thread2 = new Thread(Add); thread1.Start(); thread2.Start(); thread1.Join(); thread2.Join(); 두 Thread에서 각각 10000 번 증가시키므로 20000 을 예상할 수 있다. 하지만 실제로는 항상 정확히 20000 이 나온다고 보장할 수 없다. Race Condition 이유는 count++; 가 내부적으로 완전히 하나의 동작만 수행하는 것이 아니기 때문이다. 개념적으로는 count 읽기 ↓ + 1 계산 ↓ count에 저장 순서로 처리된다. 두 Thread가 동시에 접근하면 Thread A : count 읽기 → 10 Thread B : count 읽기 → 10 Thread A : 11 저장 Thread B : 11 저장 처럼 증가가 하나 사라질 수 있다. 이렇게 여러 Thread가 공유 데이터에 동시에 접근하면서 결과가 달라지는 문제를 Race Condition(경쟁 상태) 이라고 한다. lock 공유 데이터를 안전하게 처리해야 할 때 lock 을 사용할 수 있다. private readonly object _lockObject = new(); private int _count; void Add() { lock (_lockObject) { _count++; } } lock 영역에는 한 번에 하나의 Thread만 들어갈 수 있다. Thread A ↓ lock 획득 ↓ count 수정 ↓ lock 해제 ↓ Thread B ↓ count 수정 이를 통해 동시에 같은 데이터를 변경하면서 발생하는 문제를 막을 수 있다. Unity에서 Thread를 사용할 때 Unity에서는 Thread 사용 시 특히 주의해야 한다. 대부분의 Unity API는 Thread Safe하지 않다. 따라서 일반적으로 Unity API는 Main Thread에서 호출해야 한다. Unity 공식 문서 역시 대부분의 Unity API는 thread-safe하지 않으므로 메인 스레드에서 사용해야 한다고 설명한다. 예를 들어 Worker Thread에서 다음과 같은 코드는 피해야 한다. Thread thread = new Thread(() => { transform.position = Vector3.zero; }); Transform , GameObject , Component 등의 Unity API를 Worker Thread에서 직접 접근하면 문제가 발생할 수 있다. Thread에 적합한 작업 Thread는 Unity 객체를 직접 수정하는 작업보다 Unity API와 독립적인 계산 작업 에 적합하다. 예를 들면 대규모 숫자 계산 경로 계산 일부 데이터 처리 파일 처리 압축 / 해제 복잡한 알고리즘 같은 작업이다. 예를 들어 Thread thread = new Thread(() => { int result = HeavyCalculation(); }); 처럼 순수한 C# 계산을 별도의 Thread에서 처리할 수 있다. Coroutine과 Thread의 차이 앞에서 공부한 Coroutine과 Thread는 완전히 다른 개념이다. 구분 Coroutine Thread 실행 주로 Main Thread 별도 Thread 가능 병렬 실행 X 가능 yield 사용 사용하지 않음 Unity API 사용 가능 대부분 직접 사용 불가 주요 목적 여러 프레임에 작업 분산 별도의 실행 흐름에서 작업 예를 들어 IEnumerator AttackRoutine() { yield return new WaitForSeconds(1f); Attack(); } 은 1초 동안 별도 CPU Thread에서 실행되는 것이 아니다. Main Thread에서 실행되다가 yield 에서 중단되고 나중에 이어서 실행된다. 즉 Coroutine은 Thread가 아니다. 이 부분은 반드시 구분해야 한다. 멀티스레딩 하나의 프로그램에서 여러 Thread를 사용하는 것을 Multithreading 이라고 한다. Process │ ├─ Main Thread │ ├─ Thread A │ └─ Thread B 여러 CPU Core를 활용할 수 있는 상황이라면 서로 다른 Thread의 작업이 병렬적으로 실행될 수도 있다. 하지만 Thread가 많다고 항상 성능이 좋아지는 것은 아니다. Thread 생성과 전환에도 비용이 있고 Race Condition Deadlock 동기화 공유 데이터 관리 같은 문제도 생길 수 있다. Unity에서는 Thread를 직접 많이 사용할까? Thread 는 멀티스레딩의 기본 원리를 이해하기 위해 매우 중요한 개념이다. 다만 최신 Unity 개발에서는 항상 직접 new Thread(...) 를 만드는 것만이 정답은 아니다. Unity에는 작업에 따라 Coroutine async / await Awaitable Job System 같은 다른 선택지도 있다. 특히 최신 Unity는 Awaitable 을 제공하며, 무거운 계산을 백그라운드로 넘기는 방법도 제공한다. 따라서 이번 단계에서는 우선 Thread가 무엇이고 멀티스레딩에서 어떤 문제가 생기는지 를 이해하는 것이 중요하다. 질문 포인트 Q. Thread란? 프로세스 내부에서 코드를 실행하는 하나의 실행 흐름이다. 하나의 프로세스는 여러 Thread를 가질 수 있다. Q. Start() 와 Join() 의 차이는? Start() 는 Thread 실행을 시작하고, Join() 은 해당 Thread가 종료될 때까지 현재 Thread를 기다리게 한다. Q. Coroutine은 Thread인가? 아니다. Coroutine은 보통 Main Thread에서 실행되며 yield 를 통해 실행을 여러 프레임으로 나누는 구조이다. Q. Unity에서 Worker Thread로 GameObject를 수정해도 되는가? 대부분의 Unity API는 thread-safe하지 않으므로 일반적으로 Main Thread에서 사용해야 한다. 오늘의 정리 Thread는 하나의 실행 흐름 이다. 프로그램에는 기본적으로 Main Thread가 존재한다. new Thread() 로 별도의 Thread를 만들 수 있다. Start() 는 Thread를 실행한다. Sleep() 은 현재 Thread를 일시적으로 멈춘다. Join() 은 다른 Thread가 끝날 때까지 현재 Thread를 기다린다. 여러 Thread가 같은 데이터를 수정하면 Race Condition 이 발생할 수 있다. lock 으로 공유 데이터 접근을 동기화할 수 있다. Unity API 대부분은 Main Thread에서 사용해야 한다. Coroutine과 Thread는 완전히 다른 개념이다. 마지막으로 이 흐름을 기억하자. Process ↓ Main Thread │ ├─ Thread 생성 │ └─ Start() ↓ Worker Thread ↓ 작업 ↓ 종료 ↓ Join() 기본 코드는 다음과 같다. using System.Threading; Thread thread = new Thread(() => { // 별도의 Thread에서 실행할 작업 }); thread.Start(); thread.Join();
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
[C# / Unity] Thread(스레드) 핵심 정리. Thread 는 프로그램 안에서 코드를 실행하는 하나의 실행 흐름 이다. 하나의 프로그램에서도 여러 Thread를 사용하면 여러 작업을 나누어 처리할 수 있다. 한 줄 요약: Thread는 프로그램 내부에서 독립적으로 코드를 실행할 수 있는 하나의 작업 흐름이다. Thread란? 일반적인 프로그램은 먼저 하나의 Thread에서 실행된다. Main Thread Start() ↓ Update() ↓ Attack() ↓ Move() 코드가 하나의 실행 흐름을 따라 순서대로 실행되는 것이다. 하지만 Thread를 추가하면 Main Thread ├─ 게임 로직 ├─ 입력 처리 └─ 렌더링 관련 작업 Worker Thread └─ 별도의 계산 작업 처럼 서로…
Открыть источник