目前,我在一个项目中有多个资源,只能从一个线程访问。一个例子是ZeroMQ服务器,另一个是三菱PLC通信模块,它不是线程安全的。
现在我为任何需要单线程访问的资源创建一个单独的线程。我没有把它包装在一个类或任何东西中,所以我有一个ThreadStart
(void)方法和每个类中需要协调访问资源的几个属性。然后我使用一个结合Invoke
/ BeginInvoke
的调度程序来强制从单独的线程访问。
是否有一些类可以协调从单个线程访问资源?
以下是一些示例代码,它将立即为我提供Dispatcher:
object theLock = new object();
Dispatcher dispatcher = null;
lock (theLock)
{
new Thread(new ThreadStart(() =>
{
lock (theLock)
{
dispatcher = Dispatcher.CurrentDispatcher;
Monitor.Pulse(theLock);
}
Dispatcher.Run();
})).Start();
Monitor.Wait(theLock);
}
dispatcher.Invoke(...);
我可以将这个代码包装在一个类中,只是为了在需要时创建一个线程和调度程序,但我无法想象这是协调访问线程不安全资源的最佳解决方案。
答案 0 :(得分:3)
您是否尝试使用Task和BlockingCollection?你可以在那里排队需要访问资源的任务,并启动一个出列并运行任务的任务,一个接着一个,所以没有竞争条件?
static BlockingCollection<Action<StringBuilder>> queue = new BlockingCollection<Action<StringBuilder>>();
//Your thread unsafe resource...
static StringBuilder resource = new StringBuilder();
static void Main(string[] args)
{
Task.Factory.StartNew(() =>
{
while (true)
{
var action = queue.Take();
action(resource);
}
});
//Now to do some work you simply add something to the queue...
queue.Add((sb) => sb.Append("Hello"));
queue.Add((sb) => sb.Append(" World"));
queue.Add((sb) => Console.WriteLine("Content: {0}", sb.ToString()));
Console.ReadLine();
}
这一切都是静态的,有点难看,肯定需要返工,但应该没问题。这个想法是你将lambda想要执行,并且它们将一个接一个地执行,因此你不必在资源上进行同步。