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