Эквивалент С# для Java ExecutorService.newSingleThreadExecutor(), или: как сериализовать доступ к ресурсам с доступом к ресурсам

У меня есть пара ситуаций в моем коде, где различные потоки могут создавать рабочие элементы, которые по разным причинам не должны выполняться параллельно. Я хотел бы удостовериться, что работа выполняется в режиме FIFO, независимо от того, из какой темы она приходит. В Java я помещал рабочие элементы в однопоточное ExecutorService; есть ли эквивалент в С#? Я пробрал что-то вместе с Queue и кучей блоков lock(){}, но было бы неплохо иметь возможность использовать что-то готовое и проверенное.

Обновление: Есть ли у кого-нибудь опыт работы с System.Threading.Tasks? У этого есть решение для такого рода вещи? Я пишу приложение Monotouch, поэтому, кто знает, могу ли я даже найти его версию, которую я мог бы использовать, но по крайней мере было бы о чем подумать о будущем.

Обновление # 2 Для разработчиков С#, незнакомых с библиотеками Java, о которых я говорю, в основном я хочу что-то, что позволяет различным потокам передавать рабочие элементы таким образом, чтобы все эти рабочие элементы выполнялись на один поток (который не является ни одним из вызывающих потоков).

Ответы

Ответ 1

Вы можете использовать ConcurrentQueue (если monotouch поддерживает .net 4?), он потокобезопасен, и я думаю, что реализация фактически заблокирована. Это работает очень хорошо, если у вас многолетняя задача (например, в службе Windows).

Как правило, ваша проблема звучит так, будто у вас есть несколько продюсеров с одним потребителем.

var work = new ConcurrentQueue<Item>();
var producer1 = Task.Factory.StartNew(() => {
    work.Enqueue(item); // or whatever your threads are doing
});
var producer2 = Task.Factory.StartNew(() => {
    work.Enqueue(item); // etc
});
var consumer = Task.Factory.StartNew(() => {
    while(running) {
        Item item = null;
        work.TryDequeue(out item);
    }
});
Task.WaitAll(producer1, producer2, consumer);

Вы должны использовать BlockingCollection, если у вас есть конечный пул рабочих элементов. Здесь страница MSDN, показывающая все новые типы одновременной коллекции.

Ответ 2

Я считаю, что это можно сделать, используя SynchronizationContext. Однако я только сделал это, чтобы отправить обратно в поток пользовательского интерфейса, у которого уже есть контекст синхронизации (если сказано, что он установлен), предоставленный .NET. Я не знаю, как его подготовить для использования из "ванильного потока" "хотя.

Некоторые ссылки, которые я нашел для "custom synchronizationcontext provider" (у меня не было времени их просмотреть, не полностью понять рабочий/контекст, и у меня нет дополнительной информации):

Счастливое кодирование.

Ответ 4

Как я писал в комментариях, вы сами обнаружили, что оператор lock может выполнять эту работу.

Если вы заинтересованы в получении "контейнера", который может упростить задачу управления очередью рабочих элементов, посмотрите класс ThreadPool.

Я думаю, что в хорошо спроектированной архитектуре с помощью этих двух элементов (ThreadPool class и lock) вы можете легко и успешно сериализовать доступ к ресурсам.