我需要实现以下逻辑:
我提出了以下实现,它似乎正是我所需要的:基本上我启动一个内部线程,每隔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);
}
}
}
答案 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而不是滚动自己。