시나리오는 다음과 같습니다. 높은 우선 순위 스레드에 의해 중단 될 수있는 두 개의 낮은 우선 순위 스레드가 있습니다. 우선 순위가 높은 스레드가 우선 순위가 낮은 스레드에 일시 중지를 요청할 때마다 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;
}
}
왜 그냥 수정할 수 없습니다 할 확인'm_event.WaitOne()'아무것도없이? – usr
Thread.Priority를 사용하지 않는 것은 과감한 실수입니다. 소들이 집에 올 때까지 교착 상태를 디버깅 할 것입니다. –
뭔가가이 요구 사항에 대해 '떨어져'냄새가 났지만 그 순간에는 손가락을 대지 못했습니다. –