【问题标题】:Wait that the Threading.Timer callback function is ending等待 Threading.Timer 回调函数结束
【发布时间】:2016-06-27 18:07:55
【问题描述】:

我启动了一个带有回调函数的计时器。但是在这个回调函数中,我更改/初始化了一个在定时器启动后使用的静态对象。

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);
    }
}

当我使用静态变量时,我有一个异常“参数超出范围异常”。我认为问题在于回调函数没有完成她的执行并且对象还没有初始化。

我尝试了这个解决方案,但这不起作用:

// 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

【问题讨论】:

  • 你不应该得到一个空引用异常,你应该得到一个索引超出范围异常。您能告诉我们例外的确切措辞吗?
  • 是的,对不起,这是一个“参数超出范围异常”
  • new Timer(callbackFunct, null, 0, 10000); 无法编译。您可以发布您实际使用的代码,或者修复您的示例代码以便编译吗?
  • 您是否只想等待添加第一项?
  • @Quantic 抱歉我改了

标签: c# multithreading timer callback


【解决方案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;
        }

【讨论】:

  • 哦,好技巧,我更喜欢像我一样直接使用回调函数传递我的参数。但我会试试这个,我让你在循环中
  • 我刚刚了解了这些东西,所以它可能是错误的。但据我了解,您所遵循的示例意味着您必须使用AutoResetEvent 的回调函数,并且回调的参数必须接受事件以便它可以调用event.Set()在它上面,所以你不能只将string 作为参数传递给你的回调函数,因为它必须接受object 的事件签名,并且该对象中包含AutoResetEvent。所以对于我的自定义类,它现在也有你自己的参数了。
  • 而且不需要创建 TimerCallBack 只需传递 callbackFunct new Timer(callbackFunct, myCustomParams, 0, 10000);
【解决方案2】:

我很确定你应该用new TimerCallback(callbackFunct) 初始化你的TimerCallback 而不仅仅是函数的名称。这应该是你的列表没有被 Bobs 填满的原因(我似乎无法理解它是如何编译的,但是......)。喜欢:

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

你的函数应该是这样的:

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

也许可以在没有新实例的情况下对其进行初始化,但我不太确定...... P.S.:我怀疑这不是您使用的代码,因为它甚至没有编译。注意更新它...

【讨论】:

  • “这应该是你的名单没有被 Bobs 填满的原因”——也许,也许不是。他的代码甚至没有编译,所以很难说你的编译修复是否真的解决了他的问题,因为他必须运行 确实 编译的不同代码。
  • 我猜是这样,但是当我现在看到他的编辑时,我开始认为他的功能还可以,问题出在其他地方,因为它确实会在延迟后填满鲍勃......跨度>
猜你喜欢
  • 1970-01-01
  • 2019-01-31
  • 2018-01-17
  • 1970-01-01
  • 2019-01-06
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
相关资源
最近更新 更多