我是一名软件/硬件工程师,在C语言和嵌入式技术方面有相当多的经验。目前,我正忙于用C# (.NET)编写一些使用硬件进行数据采集的应用程序。现在,对于我来说,下面是一个问题:
例如:我有一台机器,它有一个端点开关,用于检测轴的最终位置。现在我正在使用USB数据采集模块来读取数据。目前,我正在使用线程来持续读取port-status。
此设备上没有中断功能。
我的问题是:这是正确的方式吗?我应该使用计时器、线程还是任务?我知道投票是你们大多数人“讨厌”的东西,但是任何建议都是受欢迎的!
发布于 2014-04-28 20:21:04
这在很大程度上取决于您的实际环境,但首先-在大多数情况下,您不应该再使用线程。对此,Tasks是更方便、更强大的解决方案。
Tick事件中的计时器+轮询:定时器很容易处理和停止。无需担心线程/任务在后台运行,但处理发生在主线程
Task + await Task.Delay(delay)await Task.Delay(delay)不阻塞线程池线程,但由于上下文切换,最小延迟约为15ms
Task + Thread.Sleep(delay)在1ms延迟时可用-我们实际上这样做是为了轮询我们的USB测量设备
这可以按如下方式实现:
int delay = 1;
var cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
var listener = Task.Factory.StartNew(() =>
{
while (true)
{
// poll hardware
Thread.Sleep(delay);
if (token.IsCancellationRequested)
break;
}
// cleanup, e.g. close connection
}, token, TaskCreationOptions.LongRunning, TaskScheduler.Default);在大多数情况下,您只能使用Task.Run(() => DoWork(), token),但是没有重载来提供TaskCreationOptions.LongRunning选项,该选项告诉任务调度器不要使用普通的线程池线程。
但正如您所看到的,Tasks更容易处理(并且支持await,但在这里不适用)。特别是“停止”只是从代码中的任何地方调用此实现的cancellationTokenSource.Cancel()。
您甚至可以在多个操作中共享此令牌,并立即停止它们。此外,取消令牌时不会启动尚未启动的任务。
您还可以将另一个操作附加到一个任务,以便在一个任务之后运行:
listener.ContinueWith(t => ShutDown(t));这将在监听程序完成后执行,您可以进行清理(如果未成功,t.Exception将包含tasks操作的异常)。
发布于 2014-04-28 20:22:37
无法避免IMO轮询。
您可以做的是创建一个模块,它具有独立的线程/任务,它将定期轮询端口。根据数据的变化,此模块将引发事件,该事件将由消费应用程序处理
发布于 2018-11-01 15:40:48
可能是:
public async Task Poll(Func<bool> condition, TimeSpan timeout, string message = null)
{
// https://github.com/dotnet/corefx/blob/3b24c535852d19274362ad3dbc75e932b7d41766/src/Common/src/CoreLib/System/Threading/ReaderWriterLockSlim.cs#L233
var timeoutTracker = new TimeoutTracker(timeout);
while (!condition())
{
await Task.Yield();
if (timeoutTracker.IsExpired)
{
if (message != null) throw new TimeoutException(message);
else throw new TimeoutException();
}
}
}也可以研究一下SpinWait或Task.Delay内部结构。
https://stackoverflow.com/questions/23340894
复制相似问题