c# 中是不是有任何标准的 Poller 示例类

Posted

技术标签:

【中文标题】c# 中是不是有任何标准的 Poller 示例类【英文标题】:Is there any standard Poller example class in c#c# 中是否有任何标准的 Poller 示例类 【发布时间】:2011-08-24 09:40:10 【问题描述】:

有没有 poller 类的好例子?线程安全的等待句柄、后台/前台选项以及常见的启动、停止、暂停、恢复调用?

我找到了像 CruiseControl poller 这样的例子,但理想情况下,我希望避免每次我想轮询某事时都实施 IPollable。

谢谢

【问题讨论】:

【参考方案1】:

除了基本的 .NET 计时器类之外,我不知道其他标准,但这里有一个 .NET 计时器的包装器类,它使用委托而不是您找到的包装器的 IPollable 接口。它还具有一些锁定功能和一些派上用场的方法。例如,您可能希望自己扩展和改进它以用于暂停/恢复和日志记录。祝你好运。

public class TimerWrapper

    private object defaultLock = new object();
    private object functionLock = null;
    private object classLock = new object();
    protected bool isRunning = false;
    protected bool isRepeating = false;
    protected Timer timer = null;
    protected Action timerFn = null;

    public TimerWrapper(Action timerFn)
    
        if (timerFn == null)
        
            throw new ArgumentNullException("timerFn", "Invalid timer delegate supplied at construction");
        
        // Execute this function upon expiration of the timer
        this.timerFn = timerFn;
    

    public TimerWrapper(Action timerFn, ref object timerLock) : this(timerFn)
    
        // Use the locking object passed at construction
        this.functionLock = timerLock;
    

    protected void TimerFunction(object state)
    
        if (timerFn != null)
        
            lock (classLock)
            
                // Lock on function lock if available or default lock otherwise
                lock (functionLock ?? defaultLock)
                
                    // If timer isn't repeating it's now no longer running
                    if (!IsRepeating)
                    
                        IsRunning = false;
                    

                    // Execute this function because timer has expired
                    timerFn();
                
            
        
    

    public void Stop()
    
        lock (classLock)
        
            if (timer != null)
            
                timer.Dispose();
                timer = null;
            

            IsRunning = false;
        
    

    public void Start(int duetime)
    
        // Start the timer for a single run
        Start(duetime, Timeout.Infinite);
    

    public void Start(int duetime, int period)
    
        if (duetime > 0)
        
            lock (classLock)
            
                // Stop the timer
                Stop();

                // Start the timer for either a single run or repeated runs
                timer = new Timer(TimerFunction, null, duetime, period);

                IsRunning = true;
                IsRepeating = (period != Timeout.Infinite);
            
        
    

    public bool IsRepeating
    
        get
        
            return isRepeating;
        
        protected set
        
            if (isRepeating != value)
            
                isRepeating = value;
            
        
    

    public bool IsRunning
    
        get
        
            return isRunning;
        
        protected set
        
            if (isRunning != value)
            
                isRunning = value;
            
        
    

【讨论】:

【参考方案2】:

感谢 mtijn,查看了您的示例并编写了我自己的 poller,它完成了 poller 应该做的所有事情。任何 cmets 都表示赞赏。

public class Poller

    private static readonly ILog _log = LogManager.GetLogger(typeof(Poller));

    private readonly Action _action;
    private readonly int _pollingInterval;
    private readonly Thread _processingThread;
    private readonly AutoResetEvent _stopEvent;
    private readonly ManualResetEventSlim _pauseEvent;
    private readonly object _syncLock = new object();
    private PollerState _pollerState;

    public Poller(string pollerName, Action action, int pollingInterval, bool isBackground)
    
        _action = action;
        _pollingInterval = pollingInterval;

        _stopEvent = new AutoResetEvent(false);
        _pauseEvent = new ManualResetEventSlim(false);
        _processingThread = new Thread(DoWork)  IsBackground = isBackground, Name = pollerName ;

        _pollerState = PollerState.Unstarted;
    

    public void Start()
    
        _pollerState = PollerState.Running;
        _processingThread.Start();
    

    public void Start(int dueTime)
    
        new Timer(o => Start(), null, dueTime, Timeout.Infinite);
    

    public void Stop()
    
        lock (_syncLock)
        
            if (_pollerState != PollerState.Running && _pollerState != PollerState.PauseRequested)
                _log.WarnFormat("Requested STOP on 0 poller state.", _pollerState);

            _pollerState = PollerState.StopRequested;
            _stopEvent.Set();
            _pauseEvent.Set();
        
    

    public void Pause()
    
        lock (_syncLock)
        
            if (_pollerState != PollerState.Running)
                _log.WarnFormat("Requested PAUSE on 0 poller state.", _pollerState);

            _pauseEvent.Reset();
            _pollerState = PollerState.PauseRequested;
        
    

    public void Continue()
    
        lock(_syncLock)
        
            if (_pollerState == PollerState.PauseRequested)
                _pollerState = PollerState.Running; // applicable if job is long running or no new poll was needed since pause requested
            else if (_pollerState != PollerState.Paused)
                _log.WarnFormat("Requested CONTINUE on 0 poller state.", _pollerState);
            _pauseEvent.Set();
        
    

    private void DoWork()
    
        while (_pollerState == PollerState.Running)
        
            try
            
                _action();
            
            catch(Exception ex)
            
                _log.Error(Thread.CurrentThread.Name + "failed.", ex);
            
            finally
            
                if (_stopEvent.WaitOne(_pollingInterval))
                
                    if (_pollerState == PollerState.StopRequested)
                        _pollerState = PollerState.Stopped;
                

                if (_pollerState == PollerState.PauseRequested)
                
                    _pollerState = PollerState.Paused;
                    _pauseEvent.Wait();
                    // Continue only if we are still in Pause mode and not StopRequested
                    if (_pollerState == PollerState.Paused)
                        _pollerState = PollerState.Running;
                
            
        
        _log.Debug("Exiting: " + Thread.CurrentThread.Name);
    

public enum PollerState

    Unstarted = 0,
    Running = 1,
    StopRequested = 2,
    Stopped = 3,
    PauseRequested = 4,
    Paused = 5,

【讨论】:

那么:您可以使用反射将轮询器名称设置为调用者的函数或类或线程名称,从而为您节省轮询器名称参数。您还可以使用 ctor 中的该信息初始化记录器。为了增加轮询器的可重用性,您可能需要将轮询间隔设置移动到启动方法。 start 方法当前不是线程安全的。最后,如果这是我的轮询器,我希望看到调用动作的异常而不是吞下它们。这一切都回答了你的问题吗?如果是,请标记答案。 感谢您的回复,我喜欢我自己的名字,因为它们很短,但在那里使用反射是个好主意 - 将尝试看看它在日志中的外观。您在开始时错过了锁定语句,但仍然存在到期时间过载的问题 - 不幸的是,如果调用两次,将抛出 ThreadStateException 我有自己的 catch 块在操作中以不同方式处理通信异常,如果需要,依此类推。我不希望异常停止我的轮询器。 顺便说一句,你没有处理计时器。而且我不确定在默认的 Start 方法中启动线程两次是否会在不先停止它的情况下工作。而且您不会在任何地方等待线程完成,因此无法保证在您再次调用 Start 之前它已经完成。我想我只是在 Start 上创建一个新的线程对象,我想我以前没有同样的异常。 我从没想过我可以停止并再次启动轮询器,我没有这样的情况,但它会使 threapool 更通用,线程不能再只读 - 无需处理计时器,因为没有 本课程更新 - 您是否进行了任何改进或调整?

以上是关于c# 中是不是有任何标准的 Poller 示例类的主要内容,如果未能解决你的问题,请参考以下文章

WebSockets:任何有效的 C# 示例?

C# SSL WebSocket Client 中是不是有.net 4.0?

C# 中 JSON-RPC 客户端的示例代码

缩略muduo网络库事件分发器poller

缩略muduo网络库事件分发器poller

Qt5中是不是有任何拖动移动方法?