【问题标题】:How to STOP a System.Threading.Timer如何停止 System.Threading.Timer
【发布时间】:2016-10-10 21:17:08
【问题描述】:

所以我有一个系统,您可以在其中设置叫出租车(这是一个游戏应用程序),这辆出租车需要 10 秒才能到达。问题是 我还有一个取消出租车功能,我需要知道如何停止 System.Threading.Timer,因为当他们订购出租车时,请在之后取消 让我们说 8 秒,然后在他们订购另一辆出租车之后,那辆出租车需要 2 秒而不是 10 秒,所以它仍然使用旧的出租车计时器, 我该如何阻止它?

我已经尝试过这段代码,但它仍然没有停止。当我想取消它时,我称之为 void。

public void StopTaxiTimer()
        {
            taxiTimerInstance.Dispose();
            taxiTimerInstance = null;
            this.Dispose();
        }

全班:

using log4net;
using Plus.Communication.Packets.Outgoing.Rooms.Chat;
using Plus.HabboHotel.GameClients;
using Plus.HabboHotel.Roleplay.Instance;
using Plus.HabboHotel.Rooms;
using System;
using System.Threading;

namespace Plus.HabboHotel.Roleplay.Timers
{
    public sealed class TaxiTimer : IDisposable
    {
        private static readonly ILog myLogger = LogManager.GetLogger("Plus.HabboHotel.Roleplay.Timers.DeathTimer");

        private Timer taxiTimerInstance;
        private uint timerTimeSeconds;
        private RoleplayInstance roleplayInstance;

        public TaxiTimer(RoleplayInstance roleplayInstance)
        {
            Console.WriteLine("Setup TaxiTimer for " + roleplayInstance.GetSession().GetHabbo().Username + " (" + roleplayInstance.TaxiWaitTimeSeconds + " seconds)");
            this.timerTimeSeconds = roleplayInstance.TaxiWaitTimeSeconds;
            this.roleplayInstance = roleplayInstance;
            this.taxiTimerInstance = new Timer(new TimerCallback(this.OnTimerElapsed), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
        }

        public void OnTimerElapsed(object Obj)
        {
            try
            {
                if (taxiTimerInstance == null)
                    return;

                if (roleplayInstance == null || !roleplayInstance.CalledTaxi || roleplayInstance.GetSession() == null || roleplayInstance.GetSession().GetHabbo() == null)
                    return;

                GameClient gameSession = roleplayInstance.GetSession();

                if (roleplayInstance.TaxiWaitTimeSeconds < 1)
                {
                    Room currentRoom = gameSession.GetHabbo().CurrentRoom;
                    if (currentRoom == null)
                        return;

                    RoomUser roomUser = currentRoom.GetRoomUserManager().GetRoomUserByHabbo(gameSession.GetHabbo().Id);
                    if (roomUser == null)
                        return;

                    roleplayInstance.CalledTaxi = false;
                    currentRoom.SendMessage(new ShoutComposer(roomUser.VirtualId, "*Gets transported to my destination*", 0, roomUser.LastBubble));
                    gameSession.GetHabbo().PrepareRoom(roleplayInstance.TaxiRoomId, string.Empty);
                }
                else
                {
                    roleplayInstance.TaxiWaitTimeSeconds--;
                }
            }
            catch (Exception ex)
            {
                myLogger.Error(ex.Message);
                myLogger.Error(ex.StackTrace);
            }
        }

        public void StopTaxiTimer()
        {
            taxiTimerInstance.Dispose();
            taxiTimerInstance = null;
            this.Dispose();
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }
    }
}

在 CallTaxi 上:

roleplayInstance.TaxiWaitTimeSeconds = Convert.ToUInt32(PlusEnvironment.GetRPManager().GetSettings().GetSettingValueByKey("roleplay_taxi_wait_seconds"));
                    roleplayInstance.TaxiRoomId = goingTo.RoomId;
                    roleplayInstance.TaxiTimer = new HabboHotel.Roleplay.Timers.TaxiTimer(roleplayInstance);

【问题讨论】:

标签: c# multithreading timer


【解决方案1】:

我需要知道如何停止 System.Threading.Timer,因为当他们订购出租车时,假设 8 秒后取消它,然后在他们订购另一辆出租车后立即取消,那辆出租车需要 2 秒而不是 10 秒,所以它还在用旧的计程车,怎么停?

退后一步。如果您从不制作计时器,则不必担心取消计时器。

您正在描述一个具有取消功能的异步工作流。 C# 和 .NET 框架已经具有此功能,因此请使用它而不是尝试自行开发。

创建一个async 工作流方法awaits 一个Task.Delay 任务接受CancellationToken。延误的继续是出租车的到来;取消方法通过取消令牌导致任务失败。

关于这个机制有很多文档,所以开始阅读吧。一个很好的起点在这里:

https://msdn.microsoft.com/en-us/library/dd997364

【讨论】:

    【解决方案2】:

    您的代码中似乎有很多麻烦。我看到了一些警告信号。

    您没有正确实施IDisposable。应该更像这样:

    public class ExampleDisposable : IDisposable 
    {
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (disposing) 
            {
                // free managed resources
            }
            // free native resources if there are any.
        }
    }
    

    您还为事件处理程序使用了事件引发方法命名约定。引发事件的方法通常称为On*,处理这些事件的方法是*。因此,在您的情况下,按照惯例,它应该是 public void TimerElapsed(object Obj),而不是 public void OnTimerElapsed(object Obj)

    此外,您还发现了catch (Exception ex) 的异常。这只是一个糟糕的反模式。阅读Eric Lippert's Vexing Exceptions

    现在,最后,我建议您无论如何都不要参加这种课程。改用 Microsoft 的 Reactive 框架(NuGet "System.Reactive")。

    那么你可以这样写:

    Subject<RoleplayInstance> requestTaxi = new Subject<RoleplayInstance>();
    
    IDisposable subscription =
        requestTaxi
            .Select(ri =>
                ri == null
                ? Observable.Never<RoleplayInstance>()
                : Observable
                    .Timer(TimeSpan.FromSeconds((double)ri.TaxiWaitTimeSeconds))
                    .Select(n => ri))
            .Switch()
            .Subscribe(ri =>
            {
                GameClient gameSession = ri.GetSession();
                Room currentRoom = gameSession.GetHabbo().CurrentRoom;
                RoomUser roomUser = currentRoom.GetRoomUserManager().GetRoomUserByHabbo(gameSession.GetHabbo().Id);
                currentRoom.SendMessage(new ShoutComposer(roomUser.VirtualId, "*Gets transported to my destination*", 0, roomUser.LastBubble));
                gameSession.GetHabbo().PrepareRoom(roleplayInstance.TaxiRoomId, string.Empty);
            });
    

    现在,当您想叫出租车时,您只需写 requestTaxi.OnNext(roleplayInstance);。如果您在叫到出租车之前第二次调用该事件,则事件会自动重新开始。如果您使用requestTaxi.OnNext(null); 调用它,那么它会取消任何当前请求,但仍准备好稍后处理新请求。

    如果您要完全关闭,请致电subscription.Dispose();。我认为一切都更整洁。

    【讨论】:

      【解决方案3】:

      您是否阅读了有关 Timer.Change 方法的工具提示?试试这个:

      timer.Change(Timeout.Infinite, Timeout.Infinite);
      

      【讨论】:

      • 为我工作。我有一个每秒执行一次的方法,它向控制台显示消息。我希望它在几秒钟后停止执行。我这样做了,它停止了。
      【解决方案4】:
      _timer.Change(Timeout.Infinite, Timeout.Infinite);
      _timer = null;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多