繁体   English   中英

C#SynchronizingObject和Timer.Timer线程

[英]C# SynchronizingObject and Timer.Timer thread

嗨,我想在我的主线程上使Timer.Timer类的Elapsed事件发生。 我被限制在VS 2008,.net 3.5 ......在这篇文章中: C#Timers是否在一个单独的线程上过去了? 据说使用SynchronizingObject将使处理程序在拥有该对象的线程上执行。

所以我尝试了这个:

class MyTimer
{
  private readonly Timer timer;

  public MyTimer(ISynchronizeInvoke synchronizingObject)
  {
    Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
    timer = new Timer(1000);
    timer.SynchronizingObject = synchronizingObject;
    timer.Elapsed +=
      delegate
        {
          timer.Stop();
          Thread.Sleep(2000);
          Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
          timer.Start();

        };
    timer.Start();
  }
}

class Program
{
  static void Main(string[] args)
  {
    ISynchronizeInvoke syncObject = new Control();
    var mytimer = new MyTimer(syncObject);

    Console.ReadKey();
  }
}

但输出是:1,4,4,4,4 ......

这是为什么? 如何在mainthread上执行Elapsed处理程序。

我尝试将SynchronizingObject用于事件,但这也没有帮助:

  public static ElapsedEventHandler Wrap(ElapsedEventHandler original, ISynchronizeInvoke synchronizingObject) 
  {
    return (sender, args) =>
    {
      if (synchronizingObject.InvokeRequired)
      {
        synchronizingObject.Invoke(original, new object[] { sender, args });
      }
      else
      {
        original(sender, args);
      }
    };
  }

和:

timer.Elapsed += Wrap(
      delegate
        {
          timer.Stop();
          Thread.Sleep(200);
          Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
          timer.Start();
        }, 
        synchronizingObject);

但仍然没有成功......每次InvokeRequired都是假的......

强制调试进入调用会导致无效操作:“在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke。”

最后的选择是: http//www.codeproject.com/Articles/12082/A-DelegateQueue-Classmsg = 3655119#xxx3655119xx但是真的有必要吗? 还是有一些更简单的解决方案?

我找到了一个使用DispatcherTimer和Dispatcher.Run()的解决方案来在新线程中启动消息泵。 为了停止调度员并顺利退出服务,我使用了

if (_currentDispatcher != null) _currentDispatcher.InvokeShutdown();
_thread.Join();

建议的答案没有回答原始问题,这就是为什么System.Timers.Timer Elapsed事件没有在主线程上正确触发,即使SynchronizingObject正确地设置为主线程的控件。

我自己遇到了这个问题,事实证明解决方案是因为Control还没有手柄,即使它已经正确构建了。 诀窍是将Control的Handle属性的值转换为虚拟变量,以便初始化它(参见http://blogs.msdn.com/b/jfoscoding/archive/2004/11/24/269416.aspx

但是一旦问题得到解决,它就会在原始海报的代码中产生一个新问题,因为现在存在死锁,因为Console.ReadKey()正在阻塞但是Elapsed处理程序需要在该线程上运行。 一个解决方案是执行Application.DoEvents(),尽管可能有更好的解决方案。 底线:当同步回主线程时,请勿阻塞它!

海报的原始代码经过修改以使其正常工作如下:

class MyTimer {
    private readonly System.Timers.Timer timer;
    private static AutoResetEvent elapsedOutputted = new AutoResetEvent(false);
    //private static AutoResetEvent mainReady = new AutoResetEvent(true);

    public MyTimer(ISynchronizeInvoke synchronizingObject) {

        Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        timer = new System.Timers.Timer(1000);
        timer.SynchronizingObject = synchronizingObject;
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
        //timer.Stop(); not needed
        Console.Out.WriteLine(Thread.CurrentThread.ManagedThreadId);
        elapsedOutputted.Set();
        //Thread.Sleep(2000); not needed
        //timer.Start(); not needed
    }

    static void Main(string[] args) {
        Control c = new Control();
        IntPtr tempNotUsed = c.Handle;
        var mytimer = new MyTimer(c);

        for (int runs = 0; runs < 10; runs++) {
            while (!elapsedOutputted.WaitOne(1000)) { //this will deadlock, but the 1000ms timeout will free it
                Application.DoEvents(); //not sure if DoEvents is the best idea, but it does the trick
            } //end while
        } //end for
    } //end Main
} //end class

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM