首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C# System.Timers.Timer奇数行为?

C# System.Timers.Timer奇数行为?
EN

Stack Overflow用户
提问于 2018-11-07 11:40:14
回答 1查看 921关注 0票数 1

我的目标是编写一个代码片段,允许我在并发环境中对对象(f.ex,txt文件)进行独占访问。考虑到这一点,我正在测试构建在使用两个System.Timers计时器上的简单程序。两个计时器的事件处理程序共享同一个锁对象(请参见下面的代码)。

定时器以不同的间隔同时启动,3s用于timer1,1s用于timer2。Timer1应该只工作一个周期,在此期间,它的事件处理程序将休眠10 s,从而保持锁。

令我惊讶的是,当锁被释放时,我并没有把所有的东西堆放在内存timer2事件中(只有应用程序)。他们中的每一个)。我想,虽然timer2 1的事件处理程序有锁,timer2 2的事件却堆放在内存中。但这显然不是真的。为什么会出现一些timer2事件?

代码语言:javascript
复制
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);
        }                                         
    }
}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-07 12:46:46

感谢@TheGeneral确认这是OP问题的根本原因。

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

根据医生们

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

因此线程池调度程序可能从4个线程开始。线程池调度程序非常保守。它不只是像您所要求的那样释放线程--它有时会帮助提高系统的整体性能(因为旋转线程是很昂贵的)。

要解决当前问题,可以使用以下方法提示线程池更快地旋转更多线程:

代码语言:javascript
复制
ThreadPool.SetMinThreads(50, 50);

这将使它迅速上升到50,然后更保守地在那之后。

但是,从长远来看,问题在于您正在线程池中执行长期运行的操作。这是个坏主意。您可能希望将它们移动到线程或长时间运行任务 (实际上是线程)。但这两种选择都有其不利之处。基本上,如果可能的话,您希望将长时间运行的操作保持在线程池之外。

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53188758

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档