2016-06-27 4 views
1

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

public class TimerExecute 
{ 
    // Assume that the "Dog" class exist with attribute Name initialized in the constructor 
    public static List<Dog> listDog = new List<Dog>(); 

    public void callbackFunct(String param) { 

     // code... 

     listDog.Add(new Dog("Bob")); 

     // code... 
    } 

    public void Main() { 
     // add dogs Bob each 10sec 
     Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 

     // return argumentoutofrange exception 
     Console.WriteLine(listDog[0].name); 
    } 
} 

Когда я использую статический var, у меня есть исключение «исключение вне диапазона». Я думаю, проблема заключается в том, что функция обратного вызова не завершила ее выполнение, и объект еще не инициализирован.

Я попытался это решение, но это не работает:

// add dogs Bob each 10sec 
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 
WaitHandle h = new AutoResetEvent(false); 
addbobs.Dispose(h); 
Console.WriteLine(listDog[0].name); 

Но с этим, он работает:

Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 
Thread.Sleep(2000); 
Console.WriteLine(listDog[0].name); 

Я хочу, чтобы моя функция обратного вызова завершает ее выполнение до следующей инструкции. У вас есть решение проблемы?

Последнее редактирование: Да, я хочу, чтобы иметь возможность передавать параметры callbackFunct

+1

Вы не должны получать исключение для ссылки на null, вероятно, вы должны получить исключение из диапазона исключений. Можете ли вы дать нам точную формулировку исключения? –

+0

Да, извините, это исключение из аргумента вне диапазона – Neyoh

+0

'новый таймер (callbackFunct, null, 0, 10000);' не компилируется. Можете ли вы опубликовать код, который вы используете, или исправить код примера, чтобы он компилировался? – Quantic

ответ

1

Вот что я придумал. Трюк состоит в том, чтобы передать в AutoResetEvent, и вам нужно позвонить Set() на это событие самостоятельно, что является сигналом о том, что метод «завершен» (на самом деле он просто сигнализирует о том, что метод был вызван, был ли метод выполнен или нет). Поскольку он появляется, вам нужны другие параметры, отправленные на звонок обратно в дополнение к WaitHandle, я сделал класс для инкапсуляции обоих.

 public void callbackFunct(object state) 
     { 
      var myParams = (CustomParametersWithWaitHandle)state; 
      string name = myParams.Parameter1; 
      AutoResetEvent wh = myParams.WaitHandle; 
      // code... 

      listDog.Add(new Dog(name)); 

      // code... 

      wh.Set(); // signal that this callback is done 
     } 

     public void Main() 
     { 
      // add dogs Bob each 10sec 
      AutoResetEvent wh = new AutoResetEvent(false); 
      var myCustomParams = new CustomParametersWithWaitHandle(wh, "bob", 314); 
      Timer addbobs = new Timer(new TimerCallback(callbackFunct), myCustomParams, 0, 10000); 
      wh.WaitOne(); // blocks here until `Set()` is called on the AutoResetEvent 

      Console.WriteLine(listDog[0].name); 
     } 
    } 

    public class CustomParametersWithWaitHandle 
    { 
     public AutoResetEvent WaitHandle { get; set; } 
     public string Parameter1 { get; set; } 
     public int Parameter2 { get; set; } 

     public CustomParametersWithWaitHandle(AutoResetEvent h, string parameter1, int parameter2) 
     { 
      WaitHandle = h; 
      Parameter1 = parameter1; 
      Parameter2 = parameter2; 
     } 
+0

О, хороший трюк, я предпочел бы пройти мои параметры напрямую с функцией обратного вызова, как я. Но я попробую это, я держу вас в петле – Neyoh

+0

Я только что узнал об этом, так что это может быть неправильно. Но из того, что я понимаю, приведенный ниже пример означает, что вы * имеете * использовать функцию обратного вызова для 'AutoResetEvent', а параметры обратного вызова должны принимать событие, чтобы оно могло вызывать' event.Set() 'on это значит, что вы не можете просто передать строку в качестве параметра функции обратного вызова, потому что она должна принимать подпись события 'object', и этот объект имеет в нем' AutoResetEvent'. Таким образом, с моим пользовательским классом у него теперь есть свои собственные параметры. – Quantic

+0

Это работает, спасибо – Neyoh

0

Я совершенно уверен, что вы должны инициализировать ваш TimerCallback с new TimerCallback(callbackFunct) вместо только имя функции. Это должно быть причиной того, что ваш список не заполняется Бобсом (я не могу понять, как он даже компилируется, но ...). Как:

Timer addbobs = new Timer(new TimerCallback(callbackFunct), null, 0, 10000); 

ваша функция должна выглядеть следующим образом:

public void callbackFunct(object state){ 
     //... 
     listDog.Add(new Dog("Bob")); 
     //... 
} 

Можно было бы инициализировать его без нового экземпляра, но я не совсем уверен, что ... PS: Я Подозреваю, что это не тот код, который вы используете, поскольку он даже не компилируется. Позаботьтесь об этом ...

+0

«Это должно быть причиной того, что ваш список не заполняется бобами» - может быть, может и нет. Его код даже не компилируется, поэтому трудно сказать, действительно ли исправление вашей компиляции исправляет его проблему, потому что он должен работать с другим кодом, который * делает * компиляцию. – Quantic

+0

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

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