c# - 在给定时间后等待并终止线程而不阻塞.NET 3.5

标签 c# multithreading .net-3.5

我有一个 .NET 3.5 上的 WinForms 应用程序。在这种形式下,用户触发在另一个线程(准确地说是 BackgroundWorker)中执行的操作,以免阻塞 UI 线程。我在 MVP 中,所以所有这一切都是由与 View 界面交互的演示者完成的(由 Windows 窗体实现)。到目前为止一切顺利。

我想介绍一种功能,即为后台操作引入超时时间,以便在取消操作之前完成。听起来很简单。但是后台操作调用第三方组件上的单个函数可能永远不会返回,因此 BackgroundWorker 的取消功能在这里对我没有用。此外,BackgroundWorker.RunWorkerCompleted 允许我返回到 UI 线程,因此我需要等待超时或成功并能够返回到我的调用线程(即 UI 线程)。

我尝试使用一个普通的旧线程(它支持Abort())和一个在第二个线程上运行的计时器,但似乎无法得到它可以正常工作,因为 Join() 阻塞了我的 UI 线程,尽管描述表明它将阻塞 "while continuing to perform standard COM and SendMessage pumping "。不可否认,我认为这意味着它会继续处理 Windows 消息,但事实并非如此。

int timeoutInMsec = 10000;
Thread connectThread = new Thread(Connect);
Thread timerThread = new Thread(() =>
    {
        var timer = new System.Windows.Forms.Timer() { Interval = timeoutInMsec };
        timer.Tick += (_s, _e) => 
            {
                timer.Stop();
                if (connectThread.ThreadState == ThreadState.Running)
                    connectThread.Abort();
            };
    };

connectThread.Start();
timerThread.Start();
timerThread.Join();
connectThread.Join();

基于 this question ,我尝试删除第二个计时器线程并添加 ManualResetEvent 并在计时器计时或 Connect 方法确实完成时调用 Set() 。在这里,我使用了 WaitOne 而不是 Join,但不幸的是,这也阻塞了我的 UI 线程。我还找到了this other question ,这是一个 CancellationTokenSource,遗憾的是在 .NET 3.5 中不可用。

那么,在 .NET 3.5 中,我如何启动我的工作线程并能够在给定的时间后终止它,同时又能够返回到我启动工作线程的线程执行某种 OnCompleted 处理程序?

非常感谢!

PS:我在 .NET 中的多线程编程方面没有很多经验,所以如果这是微不足道的,我很抱歉。

最佳答案

如果我正确理解你的问题,下面的算法应该可以解决你的问题:

  • 和以前一样,创建一个 BackgroundWorker 来完成您的后台工作。

  • 在 BackgroundWorker_DoWork 中,

    • 创建一个新线程(我们称之为“第三方线程”)来调用您的第三方库,然后
    • 等待第三方线程完成或超时结束。 (*)

这样,您的 UI 就不会阻塞,因为只有 Backgroundworker 线程在等待,而不是主线程。

现在谈谈有趣的部分:如何等待第三方线程完成(标有 (*) 的步骤)?

我的建议是简单地使用“循环等待 sleep ”,即(伪代码,您可以使用 Stopwatch 类作为超时):

do until (third-party thread has finished or x seconds have elapsed):
    Thread.Sleep for 100ms

if third-party thread has not finished:
    Abort it     // we don't have another choice
else
    Process the result

这不是最佳实践,但它很简单,它可以完成工作,一旦一切正常,您可以随时将其替换为花哨的跨线程同步东西(要正确实现它并非易事)。

关于c# - 在给定时间后等待并终止线程而不阻塞.NET 3.5,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42575654/

相关文章:

visual-studio-2010 - 在2.0到3.5项目转换后,Visual Studio 2010编译器看不到Web引用 namespace

c# - 在 Linq 中选择子集

C++ 对线程感到困惑

multithreading - Azure 函数的多个输入

c# - Form.show() 从另一个线程中的事件开始

c# - 如何更改报告的 "document map"根标签?

linq-to-sql - 尽管变更集中有数据,为什么Linq to sql可能无法提交更改以使更新失败

c# - 为什么 Int32 类型的最大值为 2³¹ − 1?

c# - 与 Reactive Extensions 的双向通信

c# - 计算一个数的阶乘