개요
스레드 별로 독립적임을 보장해주는 자원을 만드는 템플릿 클래스이다.
아래 예를 보면 금방 이해가 될 듯.
예1 - 기본 사용법
// 쓰레드별로 서로 다른 Counter를 갖는 싱글턴 클래스
public class ThreadLocalClass : Singleton<ThreadLocalClass>
{
// 글로벌 카운터
private static Int32 _iCounter = 0;
// 쓰레드 전용 카운터
private ThreadLocal<Int32> _iLocalCounter = new ThreadLocal<Int32>( () =>
{
return Interlocked.Increment( ref _iCounter );
}
);
public bool Init()
{
return true;
}
// 쓰레드 전용 카운터 출력
public void Print()
{
Console.WriteLine( _iLocalCounter.Value.ToString() );
}
}
class Program
{
static void MyThread()
{
while ( true )
{
ThreadLocalClass.instance.Print();
Thread.Sleep( 1000 );
}
}
static void Main( string[] args )
{
List<Thread> th = new List<Thread>();
ThreadLocalClass.instance.Init();
for ( int i = 0; i < 10; ++i )
{
th.Add( new Thread( MyThread ) );
th[i].Start();
}
Thread.Sleep( 10000 );
}
}
/* 서로 다른 숫자 10개가 반복됨.
5
1
7
2
10
8
9
4
3
6
*/
이렇게 간단하게 스레드 별로 독립적인 필드 영역을 만들 수 있다니 ㄷㄷㄷㄷㄷㄷㄷ
싱글턴에서 사용하면 매우 유용할 것 같다.
특히, 아래의 예2에서는 정말로 유용하다.
예2 - Thread-Safe 랜덤 클래스
// 쓰레드별로 서로 다른 Random을 갖는 싱글턴 클래스
public class ThreadLocalClass : Singleton<ThreadLocalClass>
{
// 글로벌 카운터
private static Int32 _iSeed = (Int32)DateTime.Now.Ticks;
// 쓰레드 전용 카운터
public ThreadLocal<Random> _random = new ThreadLocal<Random>( () => new Random(Interlocked.Increment( ref _iSeed )) );
public bool Init()
{
return true;
}
// 쓰레드 전용 카운터 출력
public int GetNextInt()
{
return _random.Value.Next();
}
}
class Program
{
static void MyThread()
{
while ( true )
{
Console.WriteLine( ThreadLocalClass.instance.GetNextInt().ToString() );
Thread.Sleep( 1000 );
}
}
static void Main( string[] args )
{
List<Thread> th = new List<Thread>();
ThreadLocalClass.instance.Init();
for ( int i = 0; i < 10; ++i )
{
th.Add( new Thread( MyThread ) );
th[i].Start();
}
Thread.Sleep( 10000 );
}
}
/*
1048112400
1977380237
2073696228
1784748255
1881064246
951796409
662848436
1688432264
759164427
855480418
*/
Random은 ThreadSafe하지 않은데, 이렇게 하면 간ㅡ단하게 ThreadSafe한 Random 사용이 가능하다.
추가)
언어단에서 지원한다기 보다는 스레드마다 어차피 스택을 갖고 있기 때문에 OS 단에서 사용하는 부분을 열어주는 거라고 한다. (정확한 정보인지는 잘 찾아보시길...)
추가적으로 ThreadStatic이 있는데, 거의 비슷함.
대신 초기화 로직을 ThreadLocal처럼 할 수 없고 따로 해줘야함... ;; (그냥 더 구지니 쓰지 않는 게...)
예1을 ThreadStatic으로 구현
// 쓰레드별로 서로 다른 Counter를 갖는 싱글턴 클래스
public class ThreadLocalClass : Singleton<ThreadLocalClass>
{
// 글로벌 카운터
private static Int32 _iCounter = 0;
// 쓰레드 전용 카운터 [쓰레드 스태틱은 개별 초기화 로직을 할 수가 없음...]
[ThreadStatic]
private static Int32 _iLocalCounter = 0;
public bool Init()
{
return true;
}
// 쓰레드 전용 카운터 출력
public void Print()
{
// 초기화 로직.
if ( _iLocalCounter == 0 )
{
_iLocalCounter = Interlocked.Increment( ref _iCounter );
}
Console.WriteLine( _iLocalCounter.ToString() );
}
}
class Program
{
static void MyThread()
{
while ( true )
{
ThreadLocalClass.instance.Print();
Thread.Sleep( 1000 );
}
}
static void Main( string[] args )
{
List<Thread> th = new List<Thread>();
ThreadLocalClass.instance.Init();
for ( int i = 0; i < 10; ++i )
{
th.Add( new Thread( MyThread ) );
th[i].Start();
}
Thread.Sleep( 10000 );
}
}
/*
1
5
6
4
2
7
8
9
10
3
*/
'Programming > C# & Unity' 카테고리의 다른 글
C# 4.0 쓸만한 기능 (0) | 2020.01.10 |
---|---|
C# 비동기 루프 및 실행 (2) | 2019.12.12 |
C# ?. ?? 연산자 (0) | 2019.10.31 |
Visual studio 2017 유니티 디버거 system.reactive.linq.observable 오류 (0) | 2018.07.03 |
Unity UI에 Onclick 넣기 (0) | 2018.03.26 |