2013-02-26 2 views
2

시나리오는 다음과 같습니다. 높은 우선 순위 스레드에 의해 중단 될 수있는 두 개의 낮은 우선 순위 스레드가 있습니다. 우선 순위가 높은 스레드가 우선 순위가 낮은 스레드에 일시 중지를 요청할 때마다 Wait 상태로 이동합니다 (대기 상태가 아닌 경우). 그러나 높은 우선 순위 스레드가 낮은 우선 순위 스레드가 Resume 일 수 있다는 신호를 보내면 우선 순위가 낮은 스레드는 우선 순위가 낮은 스레드를 중지하도록 요청한 모든 상위 스레드가 동의 할 때까지 재개되지 않아야합니다..net의 우선 순위가 높은/낮은 우선 순위 스레드 관리

이 문제를 해결하기 위해 우선 순위가 높은 스레드에서 카운터 변수의 우선 순위가 낮은 스레드에 대한 호출을 추적합니다 (Pause()). 우선 순위가 높은 스레드가 우선 순위가 낮은 스레드에 Pause()을 요청할 때마다 카운터의 값이 1 씩 증가합니다. 증가 후 카운터의 값이 1이면 스레드가 Wait이 아니므로 들어 가도록 요청합니다 Wait 상태. 그렇지 않으면 counter 값을 증가 시키십시오. 반대로 우선 순위가 높은 스레드가 Resume()을 호출하면 counter 값이 감소하고 감소 후 값이 0이면 낮은 우선 순위 스레드가 Resume이 될 수 있음을 의미합니다.

다음은 간단한 문제입니다. 비교 동작은 내부 Interlocked.XXX 함께 문 정확하지 않으면, 즉

경우 (Interlocked.Increment (REF _remain) == 1)

판독 AS/수정 및 비교 연산 원자 아니다.

무엇이 여기에 있습니까? 스레드 우선 순위를 사용하고 싶지 않습니다.

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace TestConcurrency 
{ 

// I borrowed this class from Joe Duffy's blog and modified it 
public class LatchCounter 
{ 
private long _remain; 
private EventWaitHandle m_event; 
private readonly object _lockObject; 

public LatchCounter() 
{ 
    _remain = 0; 
    m_event = new ManualResetEvent(true); 
    _lockObject = new object(); 
} 

public void Check() 
{ 
    if (Interlocked.Read(ref _remain) > 0) 
    { 
     m_event.WaitOne(); 
    } 
} 

public void Increment() 
{ 
    lock(_lockObject) 
    { 
     if (Interlocked.Increment(ref _remain) == 1) 
      m_event.Reset(); 
    } 
} 

public void Decrement() 
{ 
    lock(_lockObject) 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref _remain) == 0) 
      m_event.Set(); 
    } 
} 
} 



public class LowPriorityThreads 
{ 
private List<Thread> _threads; 
private LatchCounter _latch; 
private int _threadCount = 1; 

internal LowPriorityThreads(int threadCount) 
{ 
    _threadCount = threadCount; 
    _threads = new List<Thread>(); 
    for (int i = 0; i < _threadCount; i++) 
    { 
     _threads.Add(new Thread(ThreadProc)); 
    } 

    _latch = new CountdownLatch(); 
} 


public void Start() 
{ 
    foreach (Thread t in _threads) 
    { 
     t.Start(); 
    } 
} 

void ThreadProc() 
{ 
    while (true) 
    { 
     //Do something 
     Thread.Sleep(Rand.Next()); 
     _latch.Check(); 
    } 
} 

internal void Pause() 
{ 
    _latch.Increment(); 
} 

internal void Resume() 
{ 
    _latch.Decrement(); 
} 
} 


public class HighPriorityThreads 
{ 
private Thread _thread; 
private LowPriorityThreads _lowPriorityThreads; 

internal HighPriorityThreads(LowPriorityThreads lowPriorityThreads) 
{ 
    _lowPriorityThreads = lowPriorityThreads; 
    _thread = new Thread(RandomlyInterruptLowPriortyThreads); 
} 

public void Start() 
{ 
    _thread.Start(); 
} 

void RandomlyInterruptLowPriortyThreads() 
{ 
    while (true) 
    { 
     Thread.Sleep(Rand.Next()); 

     _lowPriorityThreads.Pause(); 

     Thread.Sleep(Rand.Next()); 
     _lowPriorityThreads.Resume(); 
    } 
} 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
    LowPriorityThreads lowPriorityThreads = new LowPriorityThreads(3); 
    HighPriorityThreads highPriorityThreadOne = new HighPriorityThreads(lowPriorityThreads); 
    HighPriorityThreads highPriorityThreadTwo = new HighPriorityThreads(lowPriorityThreads); 

    lowPriorityThreads.Start(); 
    highPriorityThreadOne.Start(); 
    highPriorityThreadTwo.Start(); 
} 
} 


class Rand 
{ 
internal static int Next() 
{ 
    // Guid idea has been borrowed from somewhere on StackOverFlow coz I like it 
    return new System.Random(Guid.NewGuid().GetHashCode()).Next() % 30000; 
} 
} 
+0

왜 그냥 수정할 수 없습니다 할 확인'm_event.WaitOne()'아무것도없이? – usr

+2

Thread.Priority를 ​​사용하지 않는 것은 과감한 실수입니다. 소들이 집에 올 때까지 교착 상태를 디버깅 할 것입니다. –

+0

뭔가가이 요구 사항에 대해 '떨어져'냄새가 났지만 그 순간에는 손가락을 대지 못했습니다. –

답변

0

귀하의 요구 사항에 대해 잘 모르겠습니다. 구현이 진행되는 한, 스레드 간 상호 작용을 처리하고 "실행 가능한"객체를위한 팩토리를 수행하는 "디스패처"클래스를 소개합니다.

구현은 물론 매우 비판적이며 비판적입니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     ThreadDispatcher td=new ThreadDispatcher(); 
     Runner r1 = td.CreateHpThread(d=>OnHpThreadRun(d,1)); 
     Runner r2 = td.CreateHpThread(d => OnHpThreadRun(d, 2)); 

     Runner l1 = td.CreateLpThread(d => Console.WriteLine("Running low priority thread 1")); 
     Runner l2 = td.CreateLpThread(d => Console.WriteLine("Running low priority thread 2")); 
     Runner l3 = td.CreateLpThread(d => Console.WriteLine("Running low priority thread 3")); 


     l1.Start(); 
     l2.Start(); 
     l3.Start(); 

     r1.Start(); 
     r2.Start(); 

     Console.ReadLine(); 

     l1.Stop(); 
     l2.Stop(); 
     l3.Stop(); 

     r1.Stop(); 
     r2.Stop(); 
    } 

    private static void OnHpThreadRun(ThreadDispatcher d,int number) 
    { 
     Random r=new Random(); 
     Thread.Sleep(r.Next(100,2000)); 
     d.CheckedIn(); 
     Console.WriteLine(string.Format("*** Starting High Priority Thread {0} ***",number)); 
     Thread.Sleep(r.Next(100, 2000)); 
     Console.WriteLine(string.Format("+++ Finishing High Priority Thread {0} +++", number)); 
     Thread.Sleep(300); 
     d.CheckedOut();   
    } 
} 

public abstract class Runner 
{ 
    private Thread _thread; 
    protected readonly Action<ThreadDispatcher> _action; 
    private readonly ThreadDispatcher _dispathcer; 
    private long _running; 
    readonly ManualResetEvent _stopEvent=new ManualResetEvent(false); 
    protected Runner(Action<ThreadDispatcher> action,ThreadDispatcher dispathcer) 
    { 
     _action = action; 
     _dispathcer = dispathcer; 
    } 

    public void Start() 
    { 
     _thread = new Thread(OnThreadStart); 
     _running = 1; 
     _thread.Start(); 
    } 

    public void Stop() 
    { 
     _stopEvent.Reset(); 
     Interlocked.Exchange(ref _running, 0); 
     _stopEvent.WaitOne(2000); 
     _thread = null; 
     Console.WriteLine("The thread has been stopped."); 

    } 
    protected virtual void OnThreadStart() 
    { 
     while (Interlocked.Read(ref _running)!=0) 
     { 
      OnStartWork(); 
      _action.Invoke(_dispathcer); 
      OnFinishWork(); 
     } 
     OnFinishWork(); 
     _stopEvent.Set(); 
    } 

    protected abstract void OnStartWork(); 
    protected abstract void OnFinishWork(); 
} 

public class ThreadDispatcher 
{ 
    private readonly ManualResetEvent _signal=new ManualResetEvent(true); 
    private int _hpCheckedInThreads; 
    private readonly object _lockObject = new object(); 

    public void CheckedIn() 
    { 
     lock(_lockObject) 
     { 
      _hpCheckedInThreads++; 
      _signal.Reset(); 
     } 
    } 
    public void CheckedOut() 
    { 
     lock(_lockObject) 
     { 
      if(_hpCheckedInThreads>0) 
       _hpCheckedInThreads--; 
      if (_hpCheckedInThreads == 0) 
       _signal.Set(); 
     } 
    } 

    private class HighPriorityThread:Runner 
    { 
     public HighPriorityThread(Action<ThreadDispatcher> action, ThreadDispatcher dispatcher) : base(action,dispatcher) 
     { 
     } 

     protected override void OnStartWork() 
     { 
     } 

     protected override void OnFinishWork() 
     { 
     } 
    } 
    private class LowPriorityRunner:Runner 
    { 
     private readonly ThreadDispatcher _dispatcher; 
     public LowPriorityRunner(Action<ThreadDispatcher> action, ThreadDispatcher dispatcher) 
      : base(action, dispatcher) 
     { 
      _dispatcher = dispatcher; 
     } 

     protected override void OnStartWork() 
     { 
      Console.WriteLine("LP Thread is waiting for a signal."); 
      _dispatcher._signal.WaitOne(); 
      Console.WriteLine("LP Thread got the signal."); 
     } 

     protected override void OnFinishWork() 
     { 

     } 
    } 

    public Runner CreateLpThread(Action<ThreadDispatcher> action) 
    { 
     return new LowPriorityRunner(action, this); 
    } 

    public Runner CreateHpThread(Action<ThreadDispatcher> action) 
    { 
     return new HighPriorityThread(action, this); 
    } 
} 

}

관련 문제