我觉得我正在重新发明轮子。将工作分派到特定线程。我想在一个线程上顺序处理来自多个线程的事件
I feel like I'm re-inventing the wheel. Dispatch work to a specific thread. I want to process events from multiple threads sequentially on one thread
我知道 WPF 和使用 Control.Invoke 方法的表单应用程序中存在类似的东西,我也知道 BackgroundWorker、ThreadPool 等的存在
但是,我不想依赖 Forms/WPF,我想确保工作 依次 和 一个 线程。
编辑:理由:我想从一个线程驱动状态机。来自其他线程的事件很艰难。没有UI.
到目前为止,我无法真正弄清楚如何使用现有框架来做到这一点 类,但我可能误解了文档。
编辑:我忘了说我绑定到 .NET Framework 3.5
到目前为止我写了什么:
public class Dispatcher
{
string Name;
Thread WorkerThread;
Queue<Action> WorkQueue;
List<Exception> Exceptions;
ManualResetEvent Gate;
volatile bool KeepRunning;
readonly object WorkLocker;
public override string ToString()
{
return String.Format("{0}({1})", this.GetType().Name, Name);
}
public Dispatcher(string name)
{
Name = name;
WorkLocker = new Object();
Gate = new ManualResetEvent(false);
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
public void Start()
{
if (WorkerThread == null)
{
WorkerThread = new Thread(doDispatch)
{
IsBackground = true,
Name = this.Name
};
WorkerThread.Start();
}
}
public void Stop()
{
if (WorkerThread != null && WorkerThread.IsAlive)
{
Dispatch(() => { KeepRunning = false; });
WorkerThread.Join();
}
WorkerThread = null;
}
public void Reset()
{
Stop();
lock (WorkLocker)
{
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
}
public void Dispatch(Action a)
{
lock (WorkLocker)
{
WorkQueue.Enqueue(a);
}
Gate.Set();
}
public List<Exception> CollectExceptions()
{
List<Exception> result = new List<Exception>();
lock(WorkLocker)
{
foreach(Exception e in Exceptions)
{
result.Add(e);
}
Exceptions.Clear();
}
return result;
}
private void doDispatch()
{
KeepRunning = true;
while (KeepRunning)
{
Gate.WaitOne();
lock (WorkLocker)
{
while (WorkQueue.Count > 0)
{
try
{
WorkQueue.Dequeue()?.Invoke();
}
catch (Exception e)
{
Exceptions.Add(e);
}
}
}
}
}
}
有没有更简单的方法来做这样的事情?另一个不错的功能是能够分派具有多个参数的调用。
由于您绑定到 3.5,因此您不能使用 BlockingCollection 或 DataFlow 库...您必须自行实施。
您提供的示例代码是一个良好的开端,但您应该应用单一职责原则,以便在(如果?)升级 .NET Framework 时使其更清晰、更容易重构。
我会这样做:
- 围绕 Queue 创建一个线程安全包装器 class
模仿 BlockingCollection,this answer provides a nice example
- 围绕 consumer/producer 流程构建代码并注入包装器
我知道 WPF 和使用 Control.Invoke 方法的表单应用程序中存在类似的东西,我也知道 BackgroundWorker、ThreadPool 等的存在
但是,我不想依赖 Forms/WPF,我想确保工作 依次 和 一个 线程。
编辑:理由:我想从一个线程驱动状态机。来自其他线程的事件很艰难。没有UI.
到目前为止,我无法真正弄清楚如何使用现有框架来做到这一点 类,但我可能误解了文档。
编辑:我忘了说我绑定到 .NET Framework 3.5
到目前为止我写了什么:
public class Dispatcher
{
string Name;
Thread WorkerThread;
Queue<Action> WorkQueue;
List<Exception> Exceptions;
ManualResetEvent Gate;
volatile bool KeepRunning;
readonly object WorkLocker;
public override string ToString()
{
return String.Format("{0}({1})", this.GetType().Name, Name);
}
public Dispatcher(string name)
{
Name = name;
WorkLocker = new Object();
Gate = new ManualResetEvent(false);
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
public void Start()
{
if (WorkerThread == null)
{
WorkerThread = new Thread(doDispatch)
{
IsBackground = true,
Name = this.Name
};
WorkerThread.Start();
}
}
public void Stop()
{
if (WorkerThread != null && WorkerThread.IsAlive)
{
Dispatch(() => { KeepRunning = false; });
WorkerThread.Join();
}
WorkerThread = null;
}
public void Reset()
{
Stop();
lock (WorkLocker)
{
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
}
public void Dispatch(Action a)
{
lock (WorkLocker)
{
WorkQueue.Enqueue(a);
}
Gate.Set();
}
public List<Exception> CollectExceptions()
{
List<Exception> result = new List<Exception>();
lock(WorkLocker)
{
foreach(Exception e in Exceptions)
{
result.Add(e);
}
Exceptions.Clear();
}
return result;
}
private void doDispatch()
{
KeepRunning = true;
while (KeepRunning)
{
Gate.WaitOne();
lock (WorkLocker)
{
while (WorkQueue.Count > 0)
{
try
{
WorkQueue.Dequeue()?.Invoke();
}
catch (Exception e)
{
Exceptions.Add(e);
}
}
}
}
}
}
有没有更简单的方法来做这样的事情?另一个不错的功能是能够分派具有多个参数的调用。
由于您绑定到 3.5,因此您不能使用 BlockingCollection 或 DataFlow 库...您必须自行实施。
您提供的示例代码是一个良好的开端,但您应该应用单一职责原则,以便在(如果?)升级 .NET Framework 时使其更清晰、更容易重构。
我会这样做:
- 围绕 Queue 创建一个线程安全包装器 class 模仿 BlockingCollection,this answer provides a nice example
- 围绕 consumer/producer 流程构建代码并注入包装器