当前位置: 首页 > 编程语言 > C#

如何让Timer跳过检查上一个线程是否还忙分享

时间:2023-04-10 22:33:19 C#

如何让Timer跳过检查上一个线程是否还忙数据库以获取新行。对于添加的每一行,我都需要在服务器上进行一些繁重的处理,有时可能需要60多秒。我在我的服务中创建了一个Timer对象,它将每60秒调用一次并调用所需的方法。因为我不想在处理发现的新行时勾选这个计时器,所以我将该方法包装在一个lock{}块中,因此其他线程无法访问该方法。它看起来像这样:定时器serviceTimer=newTimer();serviceTimer.Interval=60;serviceTimer.Elapsed+=newElapsedEventHandler(serviceTimer_Elapsed);serviceTimer.Start();voidserviceTimer_Elapsed(objectsender,ElapsedEventArgse){lock(this){//做一些繁重的处理...}}现在,我想知道-如果我的计时器滴答作响,并且在数据库中发现了很多新行,现在处理时间将超过60秒,下一个滴答将不会做任何处理,直到前一个滴答完成。这就是我想要的效果。但是现在,serviceTimer_Elapsed方法会在第一次处理完成后立即关闭,或者等待定时器再次计时。我想要发生的是-如果处理时间超过60秒,那么计时器发现线程被锁定,再等待60秒并再次检查,所以我永远不会陷入等待前一个的线程队列情况结束。我怎样才能达到这个结果?这样做的最佳做法是什么?谢谢!您可以尝试在处理过程中禁用计时器,例如//以防万一有人想继承你的类并锁定它...privatestaticobject_padlock=newobject();尝试{serviceTimer.Stop();lock(_padlock){//做一些繁重的处理...}}finally{serviceTimer.Start();编辑:OP没有指定重入是否仅由计时器引起,或者服务是否是多线程的。假设是后者,但如果是前者,那么如果计时器停止(自动重置或手动),则不需要锁定,在这种情况下您不需要锁定。在开始之前设置timer.AutoReset=false。处理完成后重新启动处理程序中的计时器。这将确保计时器在每个任务后60秒触发。快速检查它是否正在运行。如果它正在运行,它将跳过此事件并等待下一个事件触发。计时器serviceTimer=newTimer();serviceTimer.Interval=60;serviceTimer.Elapsed+=newElapsedEventHandler(serviceTimer_Elapsed);serviceTimer.Start();boolisRunning=false;voidserviceTimer_Elapsed(objectsender,ElapsedEventArgse){lock(this){if(isRunning)返回;正在运行=真;}try{//做一些繁重的处理...}finally{isRunning=false;其他答案的类似变体,仅当可用工作在锁定时完成时才允许计时器保持滴答作响,而不是在计时器停止时。把它放在传递的事件处理程序中:if(Monitor.TryEnter(locker){try{//在这里做你的工作。}finally{Monitor.Exit(locker);}}我建议你不要让计时计时器滴答作响。将计时器AutoReset设置为false。并从最后开始。这是您可能感兴趣的完整答案:Windowsservicethatneedstoexecutejobsfromajobqueueinthedatabase;Wanted:SamplecodeOtheroptionmightbetouseBackGroundWorker类或TheadPool.QueueUserWorkItem。后台工作人员可以轻松地为您提供当前正在进行的处理的选项检查并一次处理1个项目。ThreadPool将使您能够继续将项目排队到后台线程。根据您的描述,我我假设你正在检查数据库队列中的项目。在这种情况下,我会使用线程池将工作推入后台,而不是减慢/停止检查机制。对于服务,我建议你看看使用ThreadPool方法。这样你可以使用计时器每60秒检查一次新项目,然后将它们排队,然后让.Net计算为每个项目分配多少,并不断将项目推入队列。例如:如果您只使用计时器并且有5个新行,则总共需要65秒来处理。使用ThreadPool方法,这将在65秒内完成,有5个后台工作项。使用Timer方法,这将花费4分钟(每行之间等待的时间),此外这可能会导致正在排队的其他作业积压。以下是如何完成此操作的示例:TimerserviceTimer=newTimer();voidstartTimer(){serviceTimer.Interval=60;serviceTimer.Elapsed+=newElapsedEventHandler(serviceTimer_Elapsed);serviceTimer.AutoReset=false;serviceTimer.Start();}voidserviceTimer_Elapsed(objectsender,ElapsedEventArgse){try{//获取排队的工作请求行//现在将每一行推送到后台线程处理foreach(RowaRowinRowsOfRequests){ThreadPool.QueueUserWorkItem(newWaitCallback(longWorkingCode),一排);}}finally{//再等60秒,然后再次检查serviceTimer.Stop();}}voidlongWorkingCode(objectworkObject){RowworkRow=workObjectasRow;如果(workRow==null)返回;//在workRow上做你的长期工作}使用ReactiveExtensions有一个很好的解决方法。这是代码,您可以在此处阅读更完整的解释:http://www.zerobugbuild.com/?p=259publicstaticIDisposableScheduleRecurringAction(这个IScheduler调度器,TimeSpan间隔,Action动作){returnscheduler.Schedule(间隔,scheduleNext=>{action();scheduleNext(间隔);});你可以像这样使用它:TimeSpaninterval=TimeSpan.FromSeconds(5);动作work=()=>Console.WriteLine("正在做一些工作...");varschedule=Scheduler.Default.ScheduleRecurringAction(间隔,工作);Console.WriteLine("按回车停止。");控制台.ReadLine();调度.Dispose();另一种可能是这样的:以上是C#学习教程:如果前面的线程还忙,如何让Timer跳过滴答分享的全部内容,如果对你有用还需要进一步了解C#学习教程,希望大家多多关注voidserviceTimer_Elapsed(objectsender,ElapsedEventArgse){if(System.Threading.Monitor.IsLocked(yourLockingObject))return;elselock(yourLockingObject)//你的逻辑;}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: