📄 Context Switching
이전 글에서 스핀락에서는 스레드가 락 획득을 위해 while() 문에서 획득하기 전까지 무한반복하여 획득을 얻고자 한다는것을 다뤘습니다. 하지만 획득을 위한 무한루프는 큰 낭비이며, 이것을 개선하고자 다른 스레드에게 자원을 나눠줄 수 있습니다.
비슷한 세가지의 방법을 다루며, 스레드의 작업을 쉬고, 다른 스레드에게 남은 자원을 할당하여 작업하게 하는것을 Context Switching이라고 합니다.
Context Switching은 무한반복하여 획득을 얻고자하는 스레드가 있을때, 다른 스레드가 작업을 할 수 있도록 하는 장점을 가지고 있지만, Context Switching을 하기위한 작업이 적은 비용이 아니기때문에 이러한 문제를 충분히 고려해야합니다.
무조건적으로 다른 스레드에게 자원을 넘겨주는것으로 생각하지 말아야하며, 장단점이 뚜렷한 방법입니다.
📑 SpinLock, Context Switching
namespace ServerCore
{
class SpinLock
{
private volatile int mLocked = 0; //0: Unlocked, 1: Locked
public void Acquire()
{
while(true)
{
/*
매개 변수
location1 comparand 값과 비교되어 value로 바뀔 수 있는 값을 가진 대상입니다.
value 비교 결과가 같은 경우 대상 값을 바꿀 값입니다.
comparand location1의 값과 비교할 대상입니다.
반환
location1의 원래 값입니다.
*/
//리턴값이 0일경우, 언락 상태기에 1로 바꿔 다른스레드에서 사용할 수 없게 한다
//리턴값이 1인경우, 이미 언락 상태이기에 값은 변하지 않음
int expected = 0; //잠겨져있지 않을때 나올 값
int desired = 1; //잠궜을때 설정할 값
if (Interlocked.CompareExchange(ref mLocked, desired, expected) == expected) { break; }
//무조건 휴식(앙보)
//운영체제에서 스케쥴러가 1ms에 가깝게 알아서 쉬도록 한다
//무조건 1ms이지는 않음
//Thread.Sleep(1);
//조건부적으로 양보를 시도
//자신보다 우선순위가 낮은 대상에게는 양보 불가
//나보다 같거나 높은 스레드가 없다면, 현재 스레드가 계속 실행됨
//Thread.Sleep(0);
//무조건적 양보를 시도
//현재 ready 상태인 스레드가 있는지 확인 후, 해당 스레드로 전환
//ready 상태인 스레드가 없으면 현재 스레드가 계속 실행됨
Thread.Yield();
}
}
public void Release()
{
mLocked = 0;
}
}
class Program
{
static int number = 0;
static SpinLock spinLock = new SpinLock();
static void Thread1()
{
for(int i = 0; i < 1000000; ++i)
{
spinLock.Acquire();
number++;
spinLock.Release();
}
}
static void Thread2()
{
for (int i = 0; i < 1000000; ++i)
{
spinLock.Acquire();
number--;
spinLock.Release();
}
}
static void Main(string[] args)
{
Task task1 = new Task(Thread1);
Task task2 = new Task(Thread2);
task1.Start();
task2.Start();
Task.WaitAll(task1, task2);
//예상되는 출력은 0
Console.WriteLine(number);
}
}
}
Thread.Sleep(1);
Thread.Sleep(0
Thread.Yield();
- 여기서는 세 가지의 방법으로 사용이 가능합니다.
- 이 세 가지는 동작 결과는 같지만, 조금씩 차이가 존재합니다.
Thread.Sleep(1);
- 무조건적으로 스레드를 휴식(앙보)시킵니다.
- 운영체제에서 스케쥴러가 인자인 1ms에 가깝게 알아서 쉬도록 합니다.
- 입력값과 동일한 1ms로 쉬지는 않습니다.
Thread.Sleep(0);
- 조건부적으로 양보를 시도합니다.
- 자신보다 우선순위가 낮은 대상에게는 양보 불가합니다.
- 나보다 같거나 높은 스레드가 없다면, 현재 스레드가 계속 실행됩니다.
Thread.Yield();
- 무조건적 양보를 시도합니다.
- 현재 ready 상태인 스레드가 있는지 확인 후, 해당 스레드로 전환됩니다.
- 하지만 현재 ready 상태인 스레드가 없으면 현재 스레드가 계속 실행됩니다.
'server > socket server' 카테고리의 다른 글
[C# 서버] Mutex (0) | 2023.01.09 |
---|---|
[C# 서버] AutoResetEvent (1) | 2023.01.06 |
[C# 서버] 스핀락 (0) | 2023.01.04 |
[C# 서버] 원자성, Interlocked, Monitor, lock (0) | 2023.01.02 |
[C# 서버] 메모리 배리어 (0) | 2023.01.02 |