
우리가 사용하는 운영체제는 스레드로 이루어진 프로세스로 이루어져 있다.
실생활로 비유하자면, 스레드는 학생, 프로세스는 반, 운영체제는 한 학년으로 나타낼 수 있다.
오늘날 운영체제는 여러 프로세스를 동시에 실행 할 수 있는 능력을 가지고 있다. 우리가 유튜브를 들으며 비주얼 스튜디오로 코딩을 할 수 있는 것처럼 말이다.
하지만 이러한 동시에 여러가지 작업을 할 수 있는 능력은 운영체제만 할 수 있는 것이 아니다. 프로세스 와 스레드또한 할 수 있다. 우리가 워드를 사용하다보면 우리가 글을 사용하는 것을 방해하지 않으면서 문법에 맞지 않는 부분을 빨간 밑줄로 알려주는 것처럼 말이다.
프로세스는 최소 1개의 스레드로 이루어져 있다.
다르게 말하면 2개, 3개 이상의 스레드로도 이루어질 수 있다 는 뜻이다.
이처럼 1개가 아닌 여러개의 스레드를 사용하는 것 을 멀티 스레드라고 한다.
그럼 우리는 멀티 스레드를 왜 써야할까.
멀티 스레드의 장단점을 알아보자.
응답성을 높일 수 있다.
멀티스레드를 사용하면 프로그램의 응답성을 높일 수 있다.
예를 들어 단일 스레드로 만든 프로그램이 어떠한 동작을 하는데 30분이 걸릴때, 어떠한 동작을 2번 하려면 어떻게 될까?
30분동안 프로그램이 끝날때까지 기다릴 수 밖에 없다. 따라서 프로그램은 30분씩 2번, 즉 2번 프로그램을 실행하는데 1시간이나 걸리게 된다.
하지만 만약 스레드가 2개라면? 30분씩 나눠서 하여야 했던 일을 한번에 할 수 있는 것이다.
자원 공유가 쉽다.
멀티 프로세스를 사용할 떄 데이터를 교환 하려면 소켓이나 공유 메모리 같은 IPC(Inter Process Communication)을 사용해야 한다.
하지만 멀티 스레드를 쓴다면?
스레드 끼리 변수를 같이 사용하기만 하여도 데이터를 쉽게 공유 할 수 있다.
경제적이다.
새로운 프로세스를 만들기 위해 메모리와 자원을 할당하는 작업은 비용이 적지 않다.
하지만 새로운 스레드를 만드는 작업은 이미 프로세스에 할당된 데이터와 자원을 그대로 사용하므로 메모리와 자원을 할당하는 비용을 지불하지 않아도 된다.
구현이 복잡하다.
구현하기 짱짱 어렵고 생각해야 할 것도 많다.
그만큼 휴먼에러가 나기 쉽다. 이는 사용 코드를 보면 알 수 있을 것이다.
소프트웨어 안정성을 악화시킬 수 있다.
멀티 스레드의 장점이였던 "자원 공유가 쉽다."는 것이 오히려 단점으로 다가올 수 있다.
멀티 스레드는 자식 스레드 중 하나에 문제가 생기면 전체 프로세스에 영향을 주게 된다.
과용하면 성능이 저하될 수 있다.
스레드들 간의 작업전환을 하는데 적지 않은 비용이 소모된다.
따라서 너무 많은 스레드를 사용한다면 성능이 저하 될 수 있다.
이제 멀티 스레드의 장단점을 알았으니 직접 사용하여 볼 차례다.
스레드의 사용 순서는 다음과 같다.
1. Thread의 인스턴스를 생성한다. 이때, 생성자의 매개변수로 실행할 메서드를 넘긴다.
2. Thread.Start() 메서드를 호출하여 스레드를 시작한다.
3. Thread.Join() 매서드를 호출하여 스레드가 끝날 때까지 기다린다.
코드로 보면 다음과 같다.
static void DoSomething() //스레드가 실행할 메서드
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"DoSomething: {i}");
}
}
static void Main(string[] args)
{
Thread t1 = new Thread(DoSomething); //스레드의 인스턴스 생성
t1.Start(); //스레드 시작
t1.Join(); //스레드 종료 대기
}
스레드를 종료시키는 방법으로는 크게 2가지가 있다.
첫번째 방법은 Thread.Abort()함수를 이용하는 것이다.
static void DoSomething() //스레드가 실행할 메서드
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"DoSomething: {i}");
}
}
static void Main(string[] args)
{
Thread t1 = new Thread(DoSomething); //스레드의 인스턴스 생성
t1.Start(); //스레드 시작
t1.Abort(); //스레드 종료
t1.Join(); //스레드 종료 대기
}
t1.Start();를 하자마자 t1.Abort()를 하였으므로 해당 코드는 아무것도 출력되지 않고 끝나게 된다.
하지만. Thread.Abort();를 사용하면 안되는 치명적인 이유가 있다.
그 이유를 알기 위해선 스레드의 상태 변화에 대해 알아야 한다.

Thread.Abort();를 사용하게 된다면 멀티 스레드의 단점으로 말하였던
"자식 스레드 중 하나에 문제가 생기면 전체 프로세스에 영향을 주게 된다."
가 될 수 있다.
Thread.Abort();는 현재 스레드가 어떠한 상태이든 무조건 중단시키므로 현재 스레드가 해야할 작업을 모두 실행하지 않았어도 중돤 되어 오류를 발생 시킬 수 있다.
이러한 이유로 프로그래머들은 Thread.Abort()를 goto문 만큼 신중하게 사용한다.
이러한 문제를 해결하기 위해 나온 것이 Thread.Interrupt()함수이다.
Interrupt() 함수는 실행되는 스레드가 WaitSleepJoin상태가 될때까지 기다렸다 WaitSleepJoin상태가 되면 스레드를 중단시킨다.
이러한 특징 때문에 최소한 "절대로 중단되면 안 되는" 작업을 하고 있을 때는 중단되지 않는다는 보장을 받을 수 있다.
사용법 또한 Abort() 함수와 동일 하다.
static void DoSomething() //스레드가 실행할 메서드
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine($"DoSomething: {i}");
}
}
static void Main(string[] args)
{
Thread t1 = new Thread(DoSomething); //스레드의 인스턴스 생성
t1.Start(); //스레드 시작
t1.Interrupt(); //스레드 종료
t1.Join(); //스레드 종료 대기
}
Abort함수와는 달리 Interrupt를 사용하면 스레드가 해야할 일을 모두 마친 후 중단 되므로 출력이 정상적으로 작동 된 후 스레드가 중단된다.
이번 글을 쓰며 멀티 스레드와 장단점과 기초적인 사용방법에 대해 알게 되었다.
내용 및 이미지 출처: 이것이 C#이다.
너무 어려워용