2010-07-02 3 views
0

Я работаю над простой веб-службой, которая экспортирует данные из некоторого хранилища данных в базу данных.Сбой при работе с временными окнами из-за нескольких потоков

Услуга проходит каждые 20 секунд (интервал тестирования).

Интервалы реализуются через класс System.Timers.Timer.

Что происходит на данный момент:

  1. служба начинает
  2. Таймер начинает
  3. 20 секунд проходит и обслуживание начинается экспорт
  4. Экспорт не закончить в течение следующих 20 секунд, а другой нить запускает попытку сделать тот же экспорт.
  5. В конечном итоге сбой при обслуживании.

Я собирался обернуть экспорт в отдельный поток, но не уверен, полностью ли это устранит проблему.

Увеличение интервала времени не является вариантом, потому что я не уверен, насколько велика будет будущий экспорт.

Любые предложения приветствуются.

Спасибо

Edit:

Я думаю, что я после: 1. Запуск таймера 2. Начало резьбы 3. Начало экспорта 4. Не позволяйте таймер чтобы начать другой поток до тех пор, пока предыдущий не завершится ...

+0

Почему бы не иметь логическое статическое поле, чтобы отслеживать, работает ли экспорт? (и не запускать новый поток, если он есть) –

ответ

4

Как насчет в шаге 3 вы сначала отключите таймер, а затем, когда закончите с экспортом, вы снова включите таймер?

+0

+1 Чтобы добавить, зарегистрируйте обратный вызов с помощью вашей потоковой работы, чтобы обратный вызов мог снова включить таймер для вас. Однако это увеличивает интервал, на который таймер гаснет до 20 секунд + время выполнения. –

+0

Спасибо, попробовав это сейчас ... – 2010-07-02 15:28:55

+0

Исправлена ​​проблема.Спасибо! : D – 2010-07-02 15:36:49

3

Я бы сделал что-то вроде этого.

public class MyServiceController 
{ 
    private Thread m_Thread = new Thread(() => { Run(); }); 
    private ManualResetEvent m_StopSignal = new ManualResetEvent(); 

    public void Start() 
    { 
    m_Thread.Start(); 
    } 

    public void Stop() 
    { 
    m_StopSignal.Set(); // Give it chance to end on its own. 
    if (!m_Thread.Join(TimeSpan.FromSeconds(30)) 
    { 
     // Tear everything down forcefully as an absolute last resort. 
     m_Thread.Abort(); 
    } 
    } 

    private void Run() 
    { 
    while (!m_StopSignal(TimeSpan.FromSeconds(20)) 
    { 
     // Put your code here. 
    } 
    } 
} 

Этот подход выделяет отдельный выделенный поток для обработки, который сохраняет все синхронным. Обратите внимание, что для изменения интервалов используется WaitHandle. Также важно отметить, что я упустил много кода, который сделает MyServiceController более надежным, как работа с абонентами, которые хотят позвонить по телефону Start несколько раз, убедившись, что рабочий поток завершен, если он не хочет останавливаться мирно и т. Д.

+0

Собираюсь попробовать это сегодня дома, спасибо! – 2010-07-05 11:35:04

+0

Мы используем что-то подобное для нескольких клиентов. Это работает хорошо. – Junto

1

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

private static object lockObject = new object(); 
public void DoSomething() 
{ 
    if (System.Threading.Monitor.TryEnter(lockObject)) 
    { 
     try 
     { 
      // critical stuff 
     } 
     finally 
     { 
      System.Threading.Monitor.Exit(lockObject); 
     } 
    } 
} 
Смежные вопросы