繁体   English   中英

您可以向其订阅方法的单个线程,该线程将以无序方式执行

[英]A single thread to which you can subscribe methods, to be executed in an unordered fashion

我需要实现以下逻辑:

  1. 您可以在运行时订阅/取消订阅方法的线程。
  2. 所有这些方法都可以有一个标头(例如(Object sender,EventArgs e))并返回void。
  3. 这些方法的范围必须是按词法定义的类的范围。
  4. 无法保证执行顺序

我提出了以下实现,它似乎完全满足了我的需要:基本上,我启动了一个内部线程,该线程每x毫秒触发一次事件。 您可以通过适当的方法订阅/取消订阅此事件的代表。

在坚持下去之前,我想知道采用这种方法是否可能存在细微问题。

public class Orchestrator
{
    private Thread _mainThread;

    private event MethodDelegate _mainEvent;

    public delegate void MethodDelegate (Object sender, EventArgs e);

    private bool _stop = false;

    private short _ms = 100;
    public short PollingInterval { get { return _ms; }
        set
        {
            _ms = value;
        }
    }

    public Orchestrator()
    {
        _mainThread = new Thread(new ThreadStart(_execute));
    }

    public void Start()
    {
        _stop = false;
        _mainThread.Start();
    }
    public void Stop()
    {
        _stop = true;
    }

    public void Clear()
    {
        _mainEvent = null;
    }
    public void Push(MethodDelegate method)
    {
        _mainEvent += method;
    }
    public void Pop(MethodDelegate method)
    {
        _mainEvent -= method;
    }
    private void _execute()
    {
        while(!_stop)
        { 
            if (_mainEvent != null)
                try
                { 
                    _mainEvent(this, new EventArgs());
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }

            Thread.Sleep(_ms);
        }
    }
}

基本上没关系。 您需要使_stop volatile 在C#中,事件访问器方法是线程安全的,因此效果很好。

异常处理非常有问题。 您是否真的要向控制台发送垃圾邮件? 定义事件OnError并将错误报告给您的类的使用者。

您可以使用计时器或await Task.Delay保存线程。 如果同时有很多这样的类实例,这将是有意义的。 如果只有一个,这可能不值得付出努力。

在以下情况中,您有可能导致NullReferenceException的竞争条件:

    while(!_stop)
    { 
        if (_mainEvent != null)
            try
            { 
                _mainEvent(this, new EventArgs());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }

        Thread.Sleep(_ms);
    }

if (_mainEvent != null)_mainEvent的调用之间, _mainEvent其他线程可以取消订阅该事件或调用Clear()

为了避免这种情况,您应该将_mainEvent复制到本地变量中,并检查是否为null,然后改用它:

    var mainEvent = _mainEvent;
    if (mainEvent != null)
        try
        { 
            mainEvent(this, new EventArgs());

无论如何,我认为您应该为此使用Timer而不是自己动手。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM