Принудительный однопоточный доступ к ресурсу - PullRequest
4 голосов
/ 29 февраля 2012

В настоящее время у меня есть несколько ресурсов в проекте, которые могут быть доступны только из одного потока.Одним из примеров является сервер ZeroMQ, а другим - коммуникационный модуль ПЛК Mitsubishi, который не является потокобезопасным.

Сейчас я создаю отдельный поток для любого ресурса, требующего однопоточного доступа.Я не обернул это в класс или что-то еще, поэтому у меня есть метод ThreadStart (void) и пара свойств в каждом классе, требующих согласованного доступа к ресурсу.Затем я использую диспетчер в сочетании с Invoke / BeginInvoke для принудительного доступа только из отдельного потока.

Есть ли уже доступный класс, который может координировать доступ к ресурсу из одного потока?

Вот пример кода, который прямо сейчас даст мне Диспетчер:

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 Ответ

3 голосов
/ 29 февраля 2012

Вы пытались использовать 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();
}

Это все статично и немногонекрасиво и конечно нуждается в доработке, но все должно быть в порядке.Идея состоит в том, что вы ставите в очередь лямбды, которые вы хотите выполнить, и они будут выполняться одна за другой, поэтому вам не нужно синхронизироваться с ресурсом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...