該場景如下: 有一些低優先級線程可以被高優先級線程中斷。每當高優先級線程要求低優先級線程暫停時,它們將進入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