System.Threading.Timer - 我使用它了吗?

时间:2013-08-03 20:30:06

标签: c# multithreading timer

我在我的多线程应用程序中使用了一些System.Threading.Timer(s)(实际上有三个这样的计时器),但是,尽管它运行得很好,但我觉得我做错了,我消耗了不必要的资源。实际上,我正在做的是:

  1. 在我的应用程序的主窗口中(WPF窗口,但不要认为这很重要)我打开三个线程。

  2. 在这三个主题中的每一个中,我初始化并启动三个定时器中的一个

  3. 我使用三个不同线程来执行此操作的原因是因为我记得我在某个地方(无法找到哪里)读到当我开始System.Threading.Timer时我无法再使用当前线程(就像线程会在Timer启动时以某种方式停止)。

    现在,我已经测试了下一个简单的应用程序,但是Timer和启动它的线程之间似乎没有冲突。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        System.Threading.Timer _t1, _t2, _t3;
    
        private void Form1_Load(object sender, EventArgs e)
        {
            _t1 = new System.Threading.Timer(new TimerCallback(_t1Run),
                               null, TimeSpan.Zero, TimeSpan.FromMilliseconds(15));
            _t2 = new System.Threading.Timer(new TimerCallback(_t2Run),
                   null, TimeSpan.Zero, TimeSpan.FromMilliseconds(35));
            _t3 = new System.Threading.Timer(new TimerCallback(_t3Run),
                   null, TimeSpan.Zero, TimeSpan.FromMilliseconds(150));
    
            for (int i = 1; i <= 5000; i++)
            {
                Console.WriteLine("Writting on main form " + i);
            }
        }
    
        void _t1Run(object State)
        {
            _t1.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
            Console.WriteLine("running 1");
            _t1.Change(TimeSpan.FromMilliseconds(15), TimeSpan.FromMilliseconds(15));
        }
    
        void _t2Run(object State)
        {
            _t2.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
            Console.WriteLine("running 2");
            _t2.Change(TimeSpan.FromMilliseconds(35), TimeSpan.FromMilliseconds(35));
        }
    
        void _t3Run(object State)
        {
            _t3.Change(Timeout.InfiniteTimeSpan, Timeout.InfiniteTimeSpan);
            Console.WriteLine("running 3");
            _t3.Change(TimeSpan.FromMilliseconds(150), TimeSpan.FromMilliseconds(150));
        }
    
    }
    

    那么,我可以在主窗口启动所有三个定时器(或者我需要单独的线程)吗?有人可以确认这没有问题(因为在我测试的应用程序中它似乎没有任何问题)?

    修改: 这三个计时器有不同的用途,其中两个实际上有一些UI交互(一个与主窗口交互,另一个与辅助窗口交互 - 第三个只进行一些后台操作),但我不使用的原因{ {1}}定时器会进行大量操作,如果我在主线程上执行所有这些操作,那么实际上会阻止所有GUI交互(我以100-200毫秒的间隔调用那些定时器线程,所以想象一下......)。 这是我如何从定时器调用的线程进行GUI交互的一个例子:

    System.Windows.Forms.Timer

1 个答案:

答案 0 :(得分:4)

如果您在Timer回调代码中有某种类型的UI元素交互,则应使用System.Windows.Forms.Timer而不是System.Threading.Timer

每当经过时间跨度时,System.Threading.Timer都会旋转一个线程池线程。但这可能会导致Form元素出现问题,因为它们不是线程安全的。使用专用UI线程以外的线程访问UI元素可能会产生不需要的结果。

要克服此线程,应使用System.Windows.Forms.Timer的不安全行为。 System.Windows.Forms.Timer不会创建新线程或旋转新的线程池线程。它只是在UI线程中运行计时器回调。这样,所有UI交互都在单个线程中执行,这确保了线程安全性。

但是如果您的计时器回调需要大量时间才能完成,那么您的UI将会冻结,因此System.Windows.Forms.Timer应仅用于非常短的任务。 对于较长的后台任务,您可以使用System.ComponentModel.BackgroundWorker