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

时间:2015-07-25 14:13:54

标签: c# multithreading methods delegates

我需要实现以下逻辑:

  1. 您可以在运行时订阅/取消订阅方法的线程。
  2. 所有这些方法都可以有一个标题,如(Object sender,EventArgs e)并返回void。
  3. 这些方法范围必须是定义它们词法的类的范围。
  4. 无法保证执行顺序
  5. 我提出了以下实现,它似乎正是我所需要的:基本上我启动一个内部线程,每隔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);
            }
        }
    }
    

2 个答案:

答案 0 :(得分:0)

那基本上没问题。您需要制作_stop volatile。在C#中,事件访问器方法是线程安全的,因此工作正常。

异常处理非常值得怀疑。你真的想把垃圾邮件发送到控制台吗?定义事件OnError并向您的班级消费者报告错误。

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

答案 1 :(得分:0)

你有一个可能导致NullReferenceException的竞争条件:

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

        Thread.Sleep(_ms);
    }

其他一些帖子可以取消订阅该活动,也可以在Clear()if (_mainEvent != null)之间致电_mainEvent

为了避免这种情况,你应该将_mainEvent复制到一个局部变量中并检查是否为null,然后使用它:

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

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