728x90
ReaderWriterLockSlim
이 클래스는 읽기 작업과 쓰기 작업 간의 동시성을 최적화하기 위해 설계되었습니다.
ReaderWriterLockSlim은 일반적으로 읽기 작업이 많이 발생하고 쓰기 작업이 적은 상황에서 사용됩니다. 이 클래스를 사용하면 여러 스레드가 동시에 읽기 작업을 수행할 수 있지만, 쓰기 작업은 배타적으로 수행됩니다. 다시 말해, 한 스레드가 쓰기 작업을 수행하는 동안에는 다른 스레드는 읽기나 쓰기 작업을 할 수 없습니다.
평상시에는 Read락을 사용하다 특수한경우 어떤 쓰레드가 WriteLock을 사용하면 ReadLock을 사용하는 다른 모든 쓰레드는 자원을 사용하지 못하게 된다.
class Reward
{
}
static ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
static Reward GetRewardByID(int id)//일반적인 상황
{
_lock.EnterReadLock();
_lock.ExitReadLock();
return null;
}
static void AddReward(Reward reward)//특수목적 상황
{
_lock.EnterWriteLock();
_lock.ExitWriteLock();
}
static void Main(string[] arg)
{
}
ReaderWriterLockSlim 직접 만들어 보기
/// <summary>
/// 재귀적 락을 허용할지 (yes) writeLock -> WriteLock Ok, WriteLock -> ReadLock Ok, ReadLock -> WriteLock No
/// 스핀락 검색 (5000번 -> Yield
/// </summary>
internal class Lock
{
const int EMPTY_FLAG = 0x00000000;
const int WRITE_MASK = 0x7FFF0000;
const int READ_MASK = 0x0000FFFF;
const int MAX_SPIN_COUNT = 5000;
//[Unsed(1)] [WriteThreadId(15비트)] [ReadCount(16비트)]
int _flag;
int _writeCount = 0;
public void WriteLock()
{
//동일 쓰레드가 WriteLock을 이미 획득하고 있는지 확인 재귀적호출
int lockThreadId = (_flag & WRITE_MASK) >> 16;
if(Thread.CurrentThread.ManagedThreadId == lockThreadId)
{
_writeCount++;
return;
}
//아무도 WriteLock or ReadLock을 획득하고 있지 않을 때, 경합해서 소유권을 얻는다.
int desired = (Thread.CurrentThread.ManagedThreadId << 16) & WRITE_MASK;
while (true)
{
for (int i = 0; i < MAX_SPIN_COUNT; i++)
{
if (Interlocked.CompareExchange(ref _flag, desired, EMPTY_FLAG) == EMPTY_FLAG)
{
_writeCount = 1;
return;
}
////위에소스와 동일하지만 이렇게 사용하면 어셈블리에서 3번 작업을 하기 때문에 안됨.
//if(_flag == EMPTY_FLAG)//시도를 해서 성공하면 Return
// _flag = desired;//현재 쓰레드id입력
}
Thread.Yield();
}
}
public void WriteUnLock()
{
int lockCount = --_writeCount;
if (lockCount == 0)
Interlocked.Exchange(ref _flag, EMPTY_FLAG);
}
public void ReadLock()
{
//동일 쓰레드가 WriteLock을 이미 획득하고 있는지 확인 재귀적호출
int lockThreadId = (_flag & WRITE_MASK) >> 16;
if (Thread.CurrentThread.ManagedThreadId == lockThreadId)
{
Interlocked.Increment(ref _flag);
return;
}
while (true)
{
for (int i = 0; i < MAX_SPIN_COUNT; i++)
{
int expected = (_flag & READ_MASK);
if (Interlocked.CompareExchange(ref _flag, expected + 1, expected) == expected)
return;
//if ((_flag & WRITE_MASK) == 0)
//{
// _flag = _flag+1;
// return;
//}
}
Thread.Yield();
}
}
public void ReadUnLock()
{
Interlocked.Decrement(ref _flag);
}
}
728x90
'VisualStudio > C#서버' 카테고리의 다른 글
[C#서버][소스] 기본 서버, 클라이언트 소스 (0) | 2022.10.27 |
---|---|
[C#서버] TLS(Thread Local Storage) - 쓰레드로컬(ThreadLocal) (0) | 2022.10.26 |
[C#서버][개념] 임계영역와 Evnet락 (AutoResetEvent & ManualResetEvent) (0) | 2022.10.26 |
[C#서버]임계영역과 SleepLock(컨텍스트스위칭) (0) | 2022.10.26 |
[C#서버][개념] Thread.sleep 종류 (0) | 2022.10.26 |