class Program
{
static BitFlagLock locked = new BitFlagLock();
static int number = 0;
const int offset = 100000;
static void Main(string[] args)
{
Task t1 = new Task(Thread1);
Task t2 = new Task(Thread2);
t1.Start();
t2.Start();
Task.WaitAll(t1, t2);
Console.WriteLine(number);
}
static void Thread1()
{
for (int i = 0; i < offset; i++)
{
locked.WriteLock();
locked.WriteLock();
number++;
locked.WriteUnlock();
locked.WriteUnlock();
}
}
static void Thread2()
{
for (int i = 0; i < offset; i++)
{
locked.WriteLock();
number--;
locked.WriteUnlock();
}
}
}
// Unused (1) WriteThreadID (15) ReadCount (16)
class BitFlagLock
{
const int EMPTY_MASK = 0x00000000;
const int WRITE_MASK = 0x7FFF0000;
const int READ_MASK = 0x0000FFFF;
const int offset = 5000;
int flag = EMPTY_MASK;
int writerCount = 0;
private int GetCurrentWriterThreadID()
{
int writerThreadId = (flag & WRITE_MASK) >> 16;
return writerThreadId;
}
private bool IsCurrentWriterThread(Thread newWriter)
{
return GetCurrentWriterThreadID() == newWriter.ManagedThreadId;
}
// WriteLock 상태에서 WriteLock을 지원함
public void WriteLock()
{
if(IsCurrentWriterThread(Thread.CurrentThread))
{
writerCount++;
return;
}
while (true)
{
for(int i = 0; i < offset; i++)
{
// 성공 시 자신의 스레드 아이디를 Write Bit에 새기고 리턴
if (Interlocked.CompareExchange(ref flag, (Thread.CurrentThread.ManagedThreadId << 16) & WRITE_MASK, EMPTY_MASK) == EMPTY_MASK)
{
writerCount = 1;
return;
}
}
Thread.Yield();
}
}
public void WriteUnlock()
{
int lockCount = --writerCount;
if (lockCount == 0)
{
Interlocked.Exchange(ref flag, EMPTY_MASK);
}
}
public void ReadLock()
{
while(true)
{
for(int i = 0; i < offset; i++)
{
int expectedReadCount = flag & READ_MASK;
// Writer 유저 ID가 존재한다면 성공할 수 없음
// 또한, Read가 16 비트 범위 밖으로 넘어선다면 성공할 수 없다.
// Writer가 없고, Read 비트 범위 밖으로 나가지 않는다면, ReadCount++ 시켜 flag에 삽입
if (Interlocked.CompareExchange(ref flag, expectedReadCount + 1, expectedReadCount) == expectedReadCount)
return;
}
Thread.Yield();
}
}
public void ReadUnlock()
{
Interlocked.Decrement(ref flag);
}
}
ㅇ
'C#' 카테고리의 다른 글
[C#] ThreadLocalStorage? (0) | 2023.04.06 |
---|---|
[C#] 공변성, 반공변성 (0) | 2023.04.04 |
[C#] SpinLock 구현 (0) | 2023.03.29 |
[C#] IComparable과 IComparer (0) | 2023.03.26 |
[C#] Dispose 패턴 (0) | 2023.03.23 |