我在尝试用二十个timer控制二十个电磁阀的通断,要求是接到信号后延时几十毫秒,再联通几十毫秒之后断开。
多数时候没有信号但可能同一时刻多个电磁阀收到信号,也可能同一个电磁阀在几十毫秒内连续收到信号我在使用threading.timer时遇到的问题是一旦短时间内接到大量信号,部分timer好像无法正确触发,表现为个别电磁阀开启后没有正常断开而换成form.timer能保证正常通断,但同时打开的timer多了却会阻塞用户界面,另外据说form.timer是单线程的,我不知道用它是否能在同时接到多个信号时使相应的电磁阀同时打开,还是说会排队之后串行工作?请大家帮忙看看我应该采取什么控制方案,谢谢。

解决方案 »

  1.   

    timer是这样,一个timer的事件如果要执行1个小时,其它的都会阻塞等待,试试多线程
      

  2.   

    按说threading.timer就是多线程的啊,用的时候哪怕同时触发的再多再频繁也没有阻塞用户界面
    但就是隔三差五的有一个电磁阀关不上,我在timer里就做了两件事,一是控制通断,二是变一下界面上相应的label,电磁阀没关上时相应的lable也没有变化所以应该是timer没有触发没错。或者还有什么多线程方案能控制时间的?
      

  3.   

    我不知道你是如何“接到信号的”。假设放到单个线程中更合适,那么可以这样:1. 创建20个线程对应每一个电磁阀,但是不启动。
    2. 主线程只是用于轮询接收信号(当然轮询时要Sleep),每当接收到信号,对于每一个电磁阀的线程,执行Start()。线程中执行的方法执行:Sleep几十毫秒、然后联通,然后Sleep几十毫秒,然后断开,线程方法结束。我不知道当接到信号时如果电磁阀的控制线程正在执行,应该如何处理逻辑。你也没有写。但是判断线程是否Active是很容易的,.net线程有这个功能。
      

  4.   

    呃,能说下具体怎么做吗?
    多线程好办,可控制时间不还是要用到timer?
      

  5.   

    你做个实验就知道了,两个计时器都是100毫秒触发一次,但第一个计时器里有一个操作要执行1秒(我这里就是sleep(1000)替代),你会发现10秒后当第一个计时器执行了10次后第二个计时器也执行了10次,而按你的想法是第二个计时器应该执行10×10=100次了using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;namespace WindowsFormsApplication32
    {
        public partial class Form1 : Form
        {
            int A = 0, B = 0;
            Label L = null;        public Form1()
            {
                InitializeComponent();            Timer T1 = new Timer();
                T1.Interval = 100;
                T1.Tick += new EventHandler(T1_Tick);
                T1.Enabled = true;            Timer T2 = new Timer();
                T2.Interval = 100;
                T2.Tick += new EventHandler(T2_Tick);
                T2.Enabled = true;            L = new Label();
                L.Parent = this;
                L.AutoSize = true;
            }        void T2_Tick(object sender, EventArgs e)
            {
                L.Text = "第一个计时器运行了" + (++A).ToString() + "次 第二个计时器运行了" + B.ToString() + "次";
                System.Threading.Thread.Sleep(1000);
            }        void T1_Tick(object sender, EventArgs e)
            {
                L.Text = "第一个计时器运行了" + A.ToString() + "次 第二个计时器运行了" + (++B).ToString() + "次";
            }
        }
    }
      

  6.   


    十分感谢,我先去试一下
    我是有一个独立的线程在不停的分析接收到的数据并随时通过begininvoke发送信号
    所以我担心轮询的频率慢了会延缓信号相应甚至漏过信号,而频率高了(大概要一秒几十次才能保证触发的时间大致准确?)占用过多的cpu资源又会影响数据分析线程的速度……
      

  7.   

    主要是我担心线程sleep之后还要排队等操作系统相应不能马上执行,毕竟我的windows的精度就在10毫秒以上
    控制几十毫秒的延时已经有些勉强了
      

  8.   

    线程中sleep并不会使得其它线程排队,而Form.Timer实际是在主线程中触发所以才会排队。对于windows,确实有控制时序精度问题。即使WinCE那种专为工业控制而设计的,也是不能有很高的精度。
    如果这确实是个问题,可能确实需要去找找看有没有现成的第三方Timer。
      

  9.   

    to wartim:
    谢谢你的代码,我试过了,form.timer确实只能运行一个。
    to sp1234:
    精度的问题我暂时不管了,我觉得奇怪的就是明明threading.timer是多线程的,我建立的全局静态实例,用.change控制timer的开关,没有重复的建立销毁,为什么会有遗漏触发的现象?
      

  10.   

    按说不会,用form.timer时没问题说明代码在单线程下没事,而我的状态变量是用interlocked改的,应该也不存在多线程冲突。
    threading.timer归线程池管,现在怀疑可能是多个同时触发时超了.net默认的25个线程的上限。