c# timer定时器传递参数为何重复?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# timer定时器传递参数为何重复?相关的知识,希望对你有一定的参考价值。

一个Timer1,三个按钮,button1按钮传递参数1,button2按钮传递参数2,button3按钮传递参数3,
按button1时,参数传递是正确的,;按button2时,此时传递的参数是先是1后是2;按button3时,传递的参数先是1后是2最后是3;(运行程序是不要退出程序,先按button1再按button2再按button3)
我想按某个按钮,只传递一个参数,如何实现?谢谢!
private void button1_Click(object sender, EventArgs e)

string cline = "1";

timer1.Interval = 1000;
timer1.Tick += new EventHandler((s, e1) => timer1_Tick(s, e1, cline));

timer1.Start();


private void button2_Click(object sender, EventArgs e)


string cline = "2";

timer1.Interval = 1000;
timer1.Tick += new EventHandler((s, e1) => timer1_Tick(s, e1, cline));

timer1.Start();


private void button3_Click(object sender, EventArgs e)

string cline = "3";

timer1.Interval = 1000;
timer1.Tick += new EventHandler((s, e1) => timer1_Tick(s, e1, cline));

timer1.Start();


private void timer1_Tick(object sender, EventArgs e,string cl)


timer1.Stop();

MessageBox.Show(cl);

参考技术A 把timer1的定义分别放在三个按钮下面
也就是做成局部变量追问

项目环境限制,不能做成局部变量,用DISPOSE释放,也不行,不知如何处理!

追答

那就改成timer1.Tick += new EventHandler((s, e1) => timer1_Tick(s, e1));放到程序启动的时候比如form_load的时候执行一次,btn_click里面不要放这句,
同时将cline设为全局变量
btn_click里面仅仅修改全局变量cline的值,同时启动定时器

本回答被提问者和网友采纳

C# System.Timers.Timer 奇怪的行为?

【中文标题】C# System.Timers.Timer 奇怪的行为?【英文标题】:C# System.Timers.Timer odd behavior? 【发布时间】:2019-04-10 20:11:14 【问题描述】:

我的目标是编写一个代码 sn-p,让我可以在并发环境中独占访问对象(f.ex 一个 txt 文件)。考虑到这一点,我正在测试使用两个 System.Timers 计时器构建的简单程序。两个计时器的事件处理程序共享同一个锁对象(请参阅下面的代码)。 定时器以不同的时间间隔同时启动,定时器 1 为 3 秒,定时器 2 为 1 秒。 Timer1 应该只工作一个周期,在此期间它的事件处理程序将休眠 10 秒,从而保持锁定。 令我惊讶的是,当锁被释放时,我并没有把所有的事件都堆积在内存中 timer2 事件(只有应用程序。每个其他事件)。我想,虽然 timer1 的事件处理程序有锁,但 timer2 的事件在内存中堆叠。但这显然不是真的。为什么一些 timer2 事件消失了?

class Program

    static int counter = 0;
    static readonly object locker = new object();
    System.Timers.Timer timer1;
    System.Timers.Timer timer2;

    static void Main(string[] args)
    
        Program p = new Program();

        p.timer1 = new System.Timers.Timer(3000);
        p.timer1.Elapsed += new ElapsedEventHandler(p.Timer1EventHandler);
        p.timer1.Start();
        p.timer2 = new System.Timers.Timer(1000);
        p.timer2.Elapsed += new ElapsedEventHandler(p.Timer2EventHandler);
        p.timer2.Start();
        ThreadPool.SetMaxThreads(50, 50);
        Console.ReadLine();
    

    void Timer1EventHandler(object sender, ElapsedEventArgs e)
    
        timer1.Stop();
        DoThingsForTimer1Event();
    

    void DoThingsForTimer1Event()
    
        lock (locker)
        
            Console.WriteLine(DateTime.Now + " Timer1 event started." + " Current thread number " + Thread.CurrentThread.ManagedThreadId);

            Thread.Sleep(10000);

            Console.WriteLine(DateTime.Now + " Timer1 event finished. Lock released.");
        

    

    void Timer2EventHandler(object sender, ElapsedEventArgs e)
    
        counter++;
        lock (locker)
        
            Console.WriteLine(DateTime.Now + " Timer2 event fired. Current thread number " + Thread.CurrentThread.ManagedThreadId +
                " Counter=" + counter);
                                                 
    

【问题讨论】:

I don't get all stacked in memory timer2 events 你到底是什么意思,这似乎是你所期望的工作 虽然除非我读错了,但这正是它所做的 如果您对 3-8 的去向感到困惑 - 将 ++ 移入锁内 从实用的角度来看,你也不能安全地同时在多个线程中使用++。所以如果你不把它们放在锁里,你必须使用Interlocked.Increment。这对您来说还不是一个大问题(因为竞争条件很少见),但它仍然是一个问题。 我认为它只是厌倦了亲自给你线程,我的意思是线程池不会尽可能快地放弃线程。我认为如果您将时间更改为 5 秒锁定,它很可能会按预期工作 【参考方案1】:

感谢 @TheGeneral 将此确定为 OP 问题的根本原因。

您在这里遇到的主要问题是您的ThreadPool 已用尽(而您的Timer 正在使用ThreadPool),因为您的CPU 只有4 个逻辑核心。这就解释了为什么我个人(有 12 个核心)无法重现这一点。

根据the docs:

默认情况下,最小线程数设置为系统上的处理器数。

所以线程池调度程序很可能从 4 个线程开始。线程池调度程序相当保守。它不只是根据您的要求提供线程 - 有时delays creating them 可以帮助提高整体系统性能(因为启动线程很昂贵)。

要解决您的即时问题,您可以提示线程池更快地启动更多线程,使用:

ThreadPool.SetMinThreads(50, 50);

这将快速提升到 50,然后更保守。

但从长远来看,问题在于您在线程池中执行长时间运行的操作。这是一个坏主意。您可能希望将它们移动到线程或long running tasks(实际上是线程)。但这两种选择都有其缺点。从根本上说,如果可能,您希望将长时间运行的操作保留在线程池之外。

如果不了解您使用lock 的原因,很难给出好的建议。但是要考虑的一个选项可能是使用BlockingCollection 来形成一个队列 - 然后让一个单独的线程处理该队列。这意味着您的 Timer 事件只会将一个条目添加到队列中然后返回 - 处理的首当其冲将在处理来自队列的条目的(单个)线程中。

【讨论】:

以上是关于c# timer定时器传递参数为何重复?的主要内容,如果未能解决你的问题,请参考以下文章

无法通过参数传递 Timer.sheduledTimer [重复]

c#中Timer是单线程还是多线程?

C#中Timer定时器的使用示例

[C#]System.Timers.Timer

C# Timer 最简单形象的教程

如何在 C# 中创建计时器而不使用 System.Timers.Timer 或 System.Threading.Timer