强制单线程访问资源

时间:2012-02-29 12:24:21

标签: c# thread-safety dispatcher

目前,我在一个项目中有多个资源,只能从一个线程访问。一个例子是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(...);

我可以将这个代码包装在一个类中,只是为了在需要时创建一个线程和调度程序,但我无法想象这是协调访问线程不安全资源的最佳解决方案。

1 个答案:

答案 0 :(得分:3)

您是否尝试使用TaskBlockingCollection?你可以在那里排队需要访问资源的任务,并启动一个出列并运行任务的任务,一个接着一个,所以没有竞争条件?

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想要执行,并且它们将一个接一个地执行,因此你不必在资源上进行同步。