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

C# 可以订阅方法的单个线程,以无序方式执行,c#,multithreading,methods,delegates,C#,Multithreading,Methods,Delegates,我需要实现以下逻辑: 可以在运行时订阅/取消订阅方法的线程 所有这些方法都可以有一个头,比如(objectsender,EventArgs e)并返回void 这些方法的作用域必须是按词汇定义它们的类的作用域 执行的顺序没有保证 我提出了以下实现,它似乎正是我所需要的:基本上我启动一个内部线程,它每x毫秒触发一个事件。您可以通过适当的方法订阅/取消订阅此事件的代理 在坚持之前,我想知道这种方法是否会有微妙的问题 public class Orchestrator { private Th

我需要实现以下逻辑:

  • 可以在运行时订阅/取消订阅方法的线程
  • 所有这些方法都可以有一个头,比如(objectsender,EventArgs e)并返回void
  • 这些方法的作用域必须是按词汇定义它们的类的作用域
  • 执行的顺序没有保证
  • 我提出了以下实现,它似乎正是我所需要的:基本上我启动一个内部线程,它每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);
            }
        }
    }
    

    基本上没问题。您需要使
    \u停止
    不稳定
    。在C#中,事件访问器方法是线程安全的,因此工作正常

    异常处理非常可疑。是否确实要将错误发送到控制台?定义一个事件
    OnError
    ,并向类的使用者报告错误


    您可以使用计时器或等待任务。延迟来保存线程。如果同时有很多这样的类实例,这将是有意义的。如果只有一个,这可能不值得努力。

    基本上没问题。您需要使
    \u停止
    不稳定
    。在C#中,事件访问器方法是线程安全的,因此工作正常

    异常处理非常可疑。是否确实要将错误发送到控制台?定义一个事件
    OnError
    ,并向类的使用者报告错误


    您可以使用计时器或等待任务。延迟来保存线程。如果同时有很多这样的类实例,这将是有意义的。如果只有一个,这可能不值得付出努力。

    您有一个可能导致NullReferenceException的竞争条件,具体如下:

        while(!_stop)
        { 
            if (_mainEvent != null)
                try
                { 
                    _mainEvent(this, new EventArgs());
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
    
            Thread.Sleep(_ms);
        }
    
    如果(\u mainEvent!=null)和调用
    \u mainEvent
    之间,其他一些线程可以取消订阅事件或调用
    Clear()

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

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

    在任何情况下,我认为您应该为此使用计时器,而不是自己滚动。

    您有可能导致NullReferenceException的竞态条件,具体如下:

        while(!_stop)
        { 
            if (_mainEvent != null)
                try
                { 
                    _mainEvent(this, new EventArgs());
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
    
            Thread.Sleep(_ms);
        }
    
    如果(\u mainEvent!=null)
    和调用
    \u mainEvent
    之间,其他一些线程可以取消订阅事件或调用
    Clear()

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

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

    在任何情况下,我认为您都应该为此使用计时器,而不是使用自己的计时器。

    您最好使用计时器来驱动它,而不是创建自己的线程来完成。您不需要定义MethodDelegate。已经有一个EventHandler@kevin是的,这绝对是真的……忘记了,你最好使用一个来驱动它,而不是创建自己的线程来完成。你不需要定义MethodDelegate。已经有一个EventHandler@kevin是的,这绝对是真的……忘了这一点,谢谢你友好的回答。关于比赛条件你是对的。如果我简单地创建一个像var lockevent=new object()这样的对象,这不是一个解决方案吗;然后使用语句lock(lockEvent)){…}(或者使用Monitor.TryEnter()/Monitor.Exit()模式)来处理IVoke事件的代码?还有,为什么你认为我最好用定时器?在这种情况下这样做的好处是什么?计时器需要额外小心,因为多个滴答声可以同时出现,即使禁用计时器,滴答声也可能永远出现。谢谢您的友好回答。关于比赛条件你是对的。如果我简单地创建一个像var lockevent=new object()这样的对象,这不是一个解决方案吗;然后使用语句lock(lockEvent)){…}(或者使用Monitor.TryEnter()/Monitor.Exit()模式)来处理IVoke事件的代码?还有,为什么你认为我最好用定时器?在这种情况下这样做的好处是什么?计时器需要额外小心,因为多个滴答声可以同时出现,而且即使禁用计时器,滴答声也可能永远出现。谢谢您的回答。你当然是对的,你把stop声明为volatile。关于错误处理,你当然也说得对,但是为了简洁起见,我提交的代码实际上被简化了。谢谢你的回答。你当然是对的,你把stop声明为volatile。关于错误处理,你当然也说得对,但是为了简洁起见,我提交的代码实际上被简化了