该场景如下: 有一些低优先级线程可以被高优先级线程中断。每当高优先级线程要求低优先级线程暂停时,它们将进入Wait
状态(如果它们尚未处于等待状态)。然而,当高优先级的线程表示低优先级线程可以通知Resume
时,低优先级线程不应该继续,直到要求低优先级线程暂停的所有高优先级线程已经同意为止。管理.net中的高/低优先级线程
为了解决这个问题,我保持跟踪Pause()
从高优先级线程调用计数器变量中的低优先级线程。每当高优先级线程向低优先级线程询问Pause()
时,计数器的值增加1.如果在增量后计数器的值为1
,则表示该线程不在Wait
中,因此请求它进入Wait
状态。否则,只需增加counter
值。相反,当一个高优先级的线程调用Resume()
时,我们递减counter
的值,并且如果在递减之后的值是0
,这意味着低优先级的线程现在可以Resume
。
这是我的问题的简化实现。比较操作内如果与Interlocked.XXX
语句是不正确的,即
如果(Interlocked.Increment(参照_remain)== 1)
,作为读/修改和比较操作不是原子。
我在这里错过了什么?我不想使用线程优先级。
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 2013-02-26 12:14:10
不使用Thread.Priority是一个严重的错误。你将调试僵局,直到母牛回家。 – 2013-02-26 12:19:48
有些东西对这个要求闻起来有些“异味”,但我现在还不能完全掌握它。 – 2013-02-26 12:40:32