我正在研究现有项目的问题。我们想要读取ADC值,通常我们在那里使用一个“一劳永逸”的概念。我们要求输入值,并在读取值后引发事件。但是现在我必须实现一个直接返回值的函数。我的想法是用轮询来解决这个问题。
public class Information
{
public delegate void NewADCValueArrived(double newValue);
private event NewADCValueArrived newAdcValue;
private double getADCValueDirectly()
{
double value = -1;
NewADCValueArrived handler = delegate(double newValue)
{
value = newValue;
};
newAdcValue += handler;
askFornewValues(); //Fire and forget
timeout = 0;
while(value != -1 && timeout <100)
{
timeout++;
Thread.sleep(1); //Want to avoid this!! because sleeping for 1 ms is very inaccurate
}
newAdcValue -= handler;
if (value != -1)
{
return value;
}
else
{
throw Exception("Timeout");
}
}
}
现在的问题是,我想避免轮询。因为响应通常甚至超过1毫秒,我想尽快完成功能。 你有更好的想法来解决这个问题吗?
在c#-Documentation中,我找到了一些关于WaitHandlers的信息,但是我无法将它们集成到我的程序中。 (https://msdn.microsoft.com/en-us/library/system.threading.waithandle)
答案 0 :(得分:2)
您可以使用TaskCompletionSource
将事件抽象为Task
。您可以参考this question了解如何执行此操作。你甚至不需要参考答案;问题本身就说明了如何。
一旦获得Task
,您就不必再进行投票了。您可以执行各种有趣的操作,例如Wait
,ContinueWith
甚至await
。
对于超时,您可以使用TaskCompletionSource.SetCanceled
来调用Timer
。
关于如何取消订阅活动:(在评论中提问)
public class MyClass
{
public event Action OnCompletion;
}
public static Task FromEvent(MyClass obj)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
Action completion = null;
completion = () =>
{
tcs.SetResult(null);
obj.OnCompletion -= completion;
};
obj.OnCompletion += completion;
return tcs.Task;
}
答案 1 :(得分:2)
如果你有选择我可能会选择基于任务的解决方案。
否则,你可以做的是设置一个AutoResetEvent并等待事件处理程序触发它。
private double getADCValueDirectly()
{
double value = -1;
AutoResetEvent eventCompleted = new AutoResetEvent(false);
NewADCValueArrived handler = delegate(double newValue)
{
value = newValue;
// signal the waithandle
eventCompleted.Set();
};
newAdcValue += handler;
askFornewValues(); //Fire and forget
eventCompleted.WaitOne(); // optionally enter a timeout here
newAdcValue -= handler;
if (value != -1)
{
return value;
}
else
{
throw Exception("Timeout");
}
}
在http://www.albahari.com/threading/part2.aspx#_AutoResetEvent
上有一个关于C#线程处理的优秀教程答案 2 :(得分:0)
如果真的实时并且您无法让Dispatcher采取行动,那么您可以执行忙碌等待:
timeout = 0;
while(value != -1 && timeout <100000)
{
timeout++;
for(int j= 0; j < 100; j++); // keep CPU busy
}
这假设您的value
被另一个线程修改,并且您允许程序在短时间内冻结。在正面,没有窗户调度(任务,事件等)穿过你的方式。