반응형
기본 쓰레드 생성해보기
using System;
using System.Threading;
namespace ServerCore
{
class Program
{
static void MainThread()
{
Console.WriteLine("Hello, Thread!");
}
static void Main(string[] args)
{
Thread t = new Thread(MainThread);
t.Start();
Console.WriteLine("Hello, World!");
}
}
}
기본 쓰레드 생성 문법
쓰레드 관련 명령어
- .Join() - 해당 쓰레드를 기다린 후 다음 줄을 실행하겠다는 의미
- .IsBackground = t/f - 해당 쓰레드를 백그라운드로 실행할 지 여부를 결정
using System;
using System.Threading;
namespace ServerCore
{
class Program
{
static void MainThread()
{
Console.WriteLine("Hello, Thread!");
}
static void Main(string[] args)
{
Thread t = new Thread(MainThread);
t.IsBackground = true; //백그라운드로 실행할 지 여부 결정
t.Start();
Console.WriteLine("Waiting for Thread");
t.Join();//t가 끝날때까지 기다렸다가, 다음 줄을 실행하겠다
Console.WriteLine("Hello, World!");
}
}
}
쓰레드 풀링
static void MainThread(object state)
{
for(int i=0; i<5; i++)
Console.WriteLine("Hello, Thread!");
}
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(MainThread) //스레드 작업 할당
while(true) {}
}
- ThreadPool을 이용해 작업 할당, 쓰레드 최대/최소 개수 설정 등이 가능
- 이걸 통해 효율적인 쓰레드 관리가 가능
- 어느 하나가 무한루프라면, 영영 돌아오지 않아서 한 자리를 차지하고 있음_
- 그러므로 풀링은 짧은 쓰레드에 사용하는 것이 좋음
- Thread t = new Thread(); 를 쓰지 않아도, 이미 쓰레드가 생성된 상태로 진행됨
- 일이 끝나면, 대기소로 돌아감
- 즉, ThreadPool은 쓰레드의 인력 사무소_
- Thread t -> 이건 직접 알바 공고를 올려서 고용하는 것
static void MainThread(object state) { for(int i=0; i<5; i++) Console.WriteLine("Hello, Thread!"); } static void Main(string[] args) { ThreadPool.SetMinThreads(1, 1); ThreadPool.SetMaxThreads(5, 5); for (int i = 0; i < 5; i++) ThreadPool.QueueUserWorkItem((obj) => { while (true) { } }); ThreadPool.QueueUserWorkItem(MainThread); while (true) { } }
- 쓰레드 최대를 5로 설정하고, 5개의 무한루프를 생성함
- 그러면 최대 개수가 꽉 차서, MainThread가 실행되지 않음
- 즉, 오래걸리는 쓰레드를 풀링으로 붙잡아두지 말자Thread
- 자리를 먹지 않게 쓰레드 만들기
static void MainThread(object state)
{
for(int i=0; i<5; i++) Console.WriteLine("Hello, Thread!");
}
static void Main(string[] args)
{
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(5, 5);
for (int i = 0; i < 5; i++)
{
Task t = new Task(() => { while (true) { } }, TaskCreationOptions.LongRunning);
t.Start();
}
ThreadPool.QueueUserWorkItem(MainThread);
while (true) { }
}
- LongRunning 옵션을 설정하면, 미리 이건 오래걸린다고 선언을 하는 것
- ThreadPool의 좌석을 먹지 않음
- 아래 출력 사진 참고
- 아래 출력 사진 참고
- ThreadPool의 좌석을 먹지 않음
컴파일러 최적화
static bool _stop = false;
static void ThreadMain()
{
Console.WriteLine("쓰레드 시작");
while(_stop == false)
{
//누군가 stop 신호를 주기를 기다림
}
Console.WriteLine("쓰레드 종료");
}
static void Main(string[] args)
{
Task t = new Task(ThreadMain);
t.Start();
Thread.Sleep(1000);
_stop = true;
Console.WriteLine("Stop 호출");
Console.WriteLine("종료 대기중");
t.Wait();
Console.WriteLine("종료 성공");
}
- 이 코드는 디버그 모드에서는 예상한대로 돌아간다.
- 쓰레드가 실행 되고, 1초 뒤에 stop신호가 전해져 쓰레드가 정상적으로 종료됨
- 하지만 Release 모드에서는?
- 실제 배포를 진행할 때, Release모드로 진행함
- 그러면 온갖 최적화가 들어가서 프로그램이 훨씬 빨라진다
- 실제 배포를 진행할 때, Release모드로 진행함
- Release 모드에서 컴파일러가, 코드를 다음과 같이 맘대로 바꿔버린다.
- ThreadMain의 while 부분
if(_stop == false) while(true) {} //주인님이 코드를 멍청하게 짰네? 이게 더 빠르니까 이렇게 실행해야겠다.
- ThreadMain의 while 부분
- 이렇게 되면, _stop이 바뀌어도 캐치하지 못하게 되어 무한루프에 빠진다.
- _stop 선언시, volatile static bool _stop = false; 처럼 volatile 키워드를 추가한다면
- 이 변수 관련된 것은 최적화 하지 말아달라 라는 의미가 된다 -> 원래 의도한 대로 코드가 돌아감
- 하지만 권장되지 않는 방법임
- 메모리 배리어나, 락, 아토믹 같은 다른 옵션을 배워서 그걸 쓰자
- 이 변수 관련된 것은 최적화 하지 말아달라 라는 의미가 된다 -> 원래 의도한 대로 코드가 돌아감
반응형
'C# > 네트워크' 카테고리의 다른 글
[C#][서버] Lock 기초 (0) | 2024.06.02 |
---|---|
[C#][서버] Interlocked (0) | 2024.06.01 |
[C#][서버] 메모리 배리어 (0) | 2024.06.01 |
[C#][서버] 캐시 이론 (0) | 2024.05.31 |
[C#][서버] 서버 개론, 멀티쓰레드 개론 (0) | 2024.05.30 |