Что такое эффективный способ запуска задач C # в последовательности - PullRequest
4 голосов
/ 24 июня 2011

Я пытаюсь найти способ запланировать выполнение задач в последовательности.Решение, к которому я пришел, опубликовано ниже, но у меня есть подозрение, что оно может быть сделано намного проще / эффективнее.

public class SequentialTaskRunner
{
    private ISet<Task> runningTasks = new HashSet<Task>();

    public void Run(Task task)
    {
        lock (runningTasks)
        {
            var tasksToAwait = runningTasks.ToArray();

            // create a task that waits for the currently running tasks
            var waitingTask = Task.Factory.StartNew(() =>
            {
                Task.WaitAll(tasksToAwait);
            });

            // make sure the task gets removed from the running tasks on completion
            task.ContinueWith((antecedent2) =>
            {
                lock (runningTasks)
                {
                    runningTasks.Remove(task);
                }
            });

            // prepend the waiting task 
            waitingTask.ContinueWith((antecedent) => task.Start());

            runningTasks.Add(task);
        }
    }
}

Я хочу использовать это для постановки задач, связанных ссоединения через COM-порт, чтобы не допустить их попадания друг в друга.

Ситуация следующая: я работаю с устройством RFID.В игре 2 водителя.1 для чтения / записи.Еще один, который может сканировать доступные com-порты по запросу, чтобы найти (другого) читателя.Иногда для восстановления соединения используется сканирование портов с использованием драйвера устройства чтения.Именно эти 2 задачи «сканирования портов» я не хочу выполнять одновременно.

Надеюсь, это проясняет, как я попал в ситуацию, когда 2 задачи не запускались одновременно.Теперь может быть другой выход, избегая необходимости отвечать на этот вопрос.Но мне все еще очень любопытно, каким будет хорошее решение:)

Ответы [ 2 ]

4 голосов
/ 24 июня 2011

(Весь предыдущий пост поражен комментариями) .

Насколько я понимаю, у вас есть 3 типа задач.

  1. Читатель
  2. Writer
  3. Сканер портов

Вы бы хотели, чтобы эти три были как можно более параллельными, но вы также хотели бы иметь Reader, если он решит прыгнуть в порт-scanning Reconnect, чтобы не делать этого, пока сканер портов активен.Один из способов справиться с этой ситуацией - использовать Семафор .Семафоры контролируют доступ к ограниченному количеству ресурсов.

В вашем случае доступно ограниченное количество (фактически только 1) ресурсов («сканирование портов»).В этом случае мы могли бы выбрать более простой AutoResetEvent.Тем не менее, я чувствую, что Semaphore может на самом деле уменьшить путаницу.

// Only 1 task may port scan at a time
Semaphore portScanResource = new Semaphore(initialCount: 1, maximumCount: 1);

// ...

// "Reader task"
var task = Task.Factory.StartNew( () =>
    {
        // ...
        if (shouldPortScan)
        {
            portScanResource.WaitOne();
            try
            {
                // do your port scan
            }
            finally
            {
                // we're done
                portScanResource.Release();
            }
        }
    });

Задача «Сканер портов» будет использовать тот же Semaphore, гарантируя, что только 1 поток выполняет сканирование портов одновременно.

0 голосов
/ 24 июня 2011

если вы на C # 4, вы можете ConcurrentQueue класс, который является потокобезопасным для вашей очереди

или посмотреть другие классы Concurrent * в C4.Параллельные расширения также весьма удобны, но вам нужно будет настроить их на нужную вам

...