MOODv2 : Masked Image Modeling for Out-of-Distribution Detection
D2 Job Pool
1. Single Thread * # of Work ( Before )
[Diagram]
AsyncWorkProcessor : IAsyncWorkProcessor
┗━ (has) Thread
┗━ (using) Work
┗━ (is-a) DerivedRealWork
[Thread State]
① Unstarted → ② Thread.Start() → ③ Running → (④ AbortRequested, ⑤ Aborted) → ⑥ Stopped
[Work State]
①② Standby → ③ Run → (④⑤ Abort) → ⑥ Finish
[단점]
1.Thread 생성 및 종료시 오버헤드 (메모리 및 시간, 생성 및 종료 0~15ms)
2.단시간에 부하가 집중될 수 있음 (많은 요청이 들어오면 각 요청을 모두 수락)
3.작업 분산이 힘들기 때문에 급속한 FPS 변화
4.Thread Abort 및 Remove 관련 작업 불안정 (→ 수정 후 Abort 삭제)
Pool (=Work Queue) + Consumer (=Worker) Model
( After )
[Diagram]
Agent : IAsyncWorkProcessor
┗━ (has) WorkPool
┗━ (has) Worker1, Worker2, …
┗━ (has) Thread
┗━ (using) Work
┗━ (is-a) : DerivedRealWork
[API]
1.lock : 특정 객체를 Locker로 lock을 시도한다. 다른 쓰레드가 Locker를 붙잡고 있으
면 Locker가 Release 될 때까지 블록된다.
2.[Synchronization] : 해당 Property가 설정된 클래스 전체를 Thread Safe하게 보장
한다. 반드시 ContextBoundObject 클래스를 상속받아야 한다.
3.Monitor.Enter() : Locker로 lock을 시도한다. lock과 비슷하지만 Exit를 수동으로
해주어야 한다.
4.Monitor.TryEnter() : Enter()는 Locker를 얻을 때 까지 대기를 하지만 이 함수는
Locker의 획득 여부를 바로 반환해 준다.
5.Monitor.Wait() : 현재 분기에서 Locker를 Release하고 Pulse 되기 전까지 대기한
다.
6.Monitor.Pulse() : Wait()하고 있는 쓰레드를 깨운다. Pulse를 받은 쓰레드는 다시
Locker로 lock을 시도하며 성공할 경우 Wait()한 이후 구문부터 진행한다.
2. 7.Monitor.Exit() : Enter()나 TryEnter()로 획득한 lock을 해제한다.
[Main Idea]
Agent는 작업에 대한 요청(Add, Remove, Wait, WaitAll)을 받아들여 WorkPool(List로
만든 Queue)을 업데이트한다. Worker들은 일이 없으면 Wait(Sleep과 다름) 하다가
WorkPool에 작업이 들어오면 깨어나(=Pulse) 경쟁적으로 작업을 수행한다. (Thread
Safe)
[Thread State]
① Unstarted → ② Thread.Start() → (④ Monitor.Wait() → ⑤ Monitor.Pulse()) → ⑥ Running → ④ 반복
[Worker State]
①② Initializing → ③ Prepare → (④ Idle → ⑤ Prepare) → ⑥ Working → ③ 반복
[Work State]
①②③ Standby → ④ Run → ⑥ Finish
[장점]
1.Thread나 Work의 상태가 아닌 C#의 Lock 관련 API로 분기 제어가 가능
2.Thread를 미리 생성하고 프로그램이 종료될 때까지 유지하므로 Thread 생성 및 종료에
따른 오버헤드가 없음 (Abort 상태 삭제)
3.최대 Thread 갯수만큼의 작업이 진행되므로 부하가 나누어짐
4.while (조건) Sleep 대신 Monitor.Wait()와 Pulse()를 사용하여 쓰레드가 쉬고 있는 중
에는 CPU나 리소스를 거의 사용하지 않음
[Code : Worker.cs]
m_thread = new Thread(DoWork);
private void DoWork()
{
lock (this)
{
m_state = State.Prepare;
while (true)
{
lock (m_currWorkLock) m_currWork = m_pool.Pop();
if (m_currWork == null)
{
m_state = State.Prepare;
Monitor.Wait(this); // Release Lock and Sleep Until Pulse
(Idle)
continue; // Pulsed and Get Lock again (Prepare)
}
m_state = State.Working;
m_currWork.WorkProcessing();
}
}
}
[기타]
1.Worker 쓰레드의 Priority는 Lowest