Эквивалент С# для 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" (у меня не было времени их просмотреть, не полностью понять рабочий/контекст, и у меня нет дополнительной информации):
Счастливое кодирование.
Ответ 3
Не родной AFAIK, но посмотрите на это:
Оператор серийных задач; этот поток безопасен?
Ответ 4
Как я писал в комментариях, вы сами обнаружили, что оператор lock
может выполнять эту работу.
Если вы заинтересованы в получении "контейнера", который может упростить задачу управления очередью рабочих элементов, посмотрите класс ThreadPool
.
Я думаю, что в хорошо спроектированной архитектуре с помощью этих двух элементов (ThreadPool
class и lock
) вы можете легко и успешно сериализовать доступ к ресурсам.