首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以正确的方式进行投票?

以正确的方式进行投票?
EN

Stack Overflow用户
提问于 2014-04-28 20:15:14
回答 3查看 37.2K关注 0票数 24

我是一名软件/硬件工程师,在C语言和嵌入式技术方面有相当多的经验。目前,我正忙于用C# (.NET)编写一些使用硬件进行数据采集的应用程序。现在,对于我来说,下面是一个问题:

例如:我有一台机器,它有一个端点开关,用于检测轴的最终位置。现在我正在使用USB数据采集模块来读取数据。目前,我正在使用线程来持续读取port-status。

此设备上没有中断功能。

我的问题是:这是正确的方式吗?我应该使用计时器、线程还是任务?我知道投票是你们大多数人“讨厌”的东西,但是任何建议都是受欢迎的!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-04-28 20:21:04

这在很大程度上取决于您的实际环境,但首先-在大多数情况下,您不应该再使用线程。对此,Tasks是更方便、更强大的解决方案。

  • 低轮询频率:Tick事件中的计时器+轮询:

定时器很容易处理和停止。无需担心线程/任务在后台运行,但处理发生在主线程

  • 中轮询频率:Task + await Task.Delay(delay)await Task.Delay(delay)不阻塞线程池线程,但由于上下文切换,最小延迟约为15ms

  • 高轮询频率:Task + Thread.Sleep(delay)

在1ms延迟时可用-我们实际上这样做是为了轮询我们的USB测量设备

这可以按如下方式实现:

代码语言:javascript
复制
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()

您甚至可以在多个操作中共享此令牌,并立即停止它们。此外,取消令牌时不会启动尚未启动的任务。

您还可以将另一个操作附加到一个任务,以便在一个任务之后运行:

代码语言:javascript
复制
listener.ContinueWith(t => ShutDown(t));

这将在监听程序完成后执行,您可以进行清理(如果未成功,t.Exception将包含tasks操作的异常)。

票数 51
EN

Stack Overflow用户

发布于 2014-04-28 20:22:37

无法避免IMO轮询。

您可以做的是创建一个模块,它具有独立的线程/任务,它将定期轮询端口。根据数据的变化,此模块将引发事件,该事件将由消费应用程序处理

票数 2
EN

Stack Overflow用户

发布于 2018-11-01 15:40:48

可能是:

代码语言:javascript
复制
   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();
            }
        }
    }

也可以研究一下SpinWaitTask.Delay内部结构。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23340894

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档