2010-10-14 7 views
2

Я использую System.Threading.Timer в моей службе Windows и блокирую метод обратного вызова с использованием Monitor.TryEnter, поэтому он не реентерабелен. Внутри обратного вызова я перебираю некоторые объекты базы данных (объекты Linq to SQL) и выполняю некоторые задачи ввода-вывода. На каждой итерации цикла я меняю некоторые свойства сущности, чтобы отметить ее как обработанную. После выхода цикла я вызываю SubmitChanges в datacontext, который сохраняет изменения в базе данных. Возникает следующая проблема: если служба останавливается во время выполнения обратного вызова, некоторые из задач ввода-вывода могут быть уже выполнены, но записи не были отмечены как обработанные в базе данных (например, SubmitChanges еще не вызывается) - очевидно, не то, что я хочу. Каким-то образом мне нужно связаться с потоком рабочего обратного вызова, которое событие OnStop уволило, чтобы позволить ему отправлять изменения и обертывать вещи. Как лучше всего это сделать?Изящно остановить поток обратного вызова таймера

+0

Я предположил, что ваша проблема в том, что, убивая таймер, который вы будете убить выполнение функции обратного вызова таймера, правильно ли это? –

+0

Не совсем. Я должен быть более ясным; Я понимаю, что остановка таймера просто прекращает его снова стрелять, но не убивает метод обратного вызова. Однако некоторые из задач ввода-вывода могут быть длительными - может быть, несколько минут. Я не хочу, чтобы пользователь (или система) принудительно прервал процесс, если он слишком долго. Я бы предпочел, чтобы это обслуживание закончилось изящно. – Antony

+0

Ну, у службы управления есть метод RequestMoreTime() или что-то в этом роде (я говорю из памяти), с помощью которого вы можете продлить время своего обслуживания и все еще не быть повешенным для SCM. –

ответ

1

1-й решает, завершите ли вы выполнение задач обратного вызова или отложите их. Поэтому, если вы решите закончить задачи, вы выполните обратный вызов до конца. Время должно быть отменено в OnStop уже. Если вы будете ехать со вторым вариантом (откатом) ваш код будет выглядеть примерно так:

bool shouldAbort=false; 

TimerProc() 
{ 
    Step1(); 
    if (shouldAbort) 
    { 
     UndoStep1(); 
     return; 
    } 
    Step2(); 
    if (shouldAbort) 
    { 
     UndoStep2(); 
     UndoStep1(); // or vice versa, depending on your operations 
     return; 
    } 
    // ... 
} 

в OnStop()

timer.Stop(); // don't worry here - your TimerProc() WILL finish 
shouldAbort=true; 
+0

, если у вас есть проблемы с TimerProc(), которые не выполняются, используйте AutoResetEvent и WaitOne() после убийства таймера и Set() событие в конце TimerProc() –

+0

Спасибо за предложение. * * * остановить таймер в OnStop: timer.Change (Timeout.Infinite, 0) - использовать таймер из пространства имен Threading. Но я также хочу сигнализировать обратный вызов поток, который нужно быстро завершить (без отката). Возможно, сценарий, который делает необходимость более очевидным, - это событие выключения. – Antony

+1

Есть два Антониса: тот, кто хочет, чтобы задача быстро завершилась, а другая, которая не хочет долгое время i/o задачи, которые нужно насильственно убить. Надо отказаться, давайте дать им некоторое время, чтобы решить :) –

0

Вы можете посмотреть на использование Task Parallel Library. Прочтите страницу Task Cancellation. Это даст вам возможность создать рабочие потоки, которые могут быть аккуратно очищены в ответ на отмену, если я правильно понял ваши потребности.

+0

Выглядит очень интересно, но, к сожалению, я все еще использую Framework 3.5 :( – Antony

Смежные вопросы