线程-如何通过UI交互终止工作/后台线程

如何解决线程-如何通过UI交互终止工作/后台线程

|| Compact Framework,Windows Mobile 6,C#。 我正在使用紧凑型框架上的一些后台线程,并且有一个问题要问:终止工作线程。 代码 我有以下ThreadWorker类(此处的代码),该类在执行时将在某些点执行检查,以查看是否应该退出。
public class ThreadWorker 
{

    public event EventHandler<ProgressEventArgs> OnProgress;

    protected virtual void Progress(ProgressEventArgs args)
    {
        if (OnProgress != null)
            OnProgress(this,args);
    }

    private void DoLongProcess()
    {
        // This will take a long time.
        Thread.Sleep(15000);
        Progress(new ProgressEventArgs(\"Some info for the UI to display.\"));
        Thread.Sleep(15000);
    }

    public void DoSomeBackgroundWork()
    {
        try
        {
            while (!Stopping)
            {
                DoLongProcess();
                if (Stopping) return;

                DoLongProcess();
                if (Stopping) return;

                DoLongProcess();
                if (Stopping) return;

                DoLongProcess();
                if (Stopping) return;
            }
        }
        finally
        {
            SetStopped();
        }

        Console.WriteLine(\"DoSomeBackgroundWork: Terminating gracefully.\");
    }

    /// <summary>
    /// Lock covering stopping and stopped
    /// </summary>
    readonly object locker = new object();

    /// <summary>
    /// Whether or not the worker thread has been asked to stop
    /// </summary>
    bool stopping = false;

    /// <summary>
    /// Whether or not the worker thread has stopped
    /// </summary>
    bool stopped = false;

    /// <summary>
    /// Returns whether the worker thread has been asked to stop.
    /// This continues to return true even after the thread has stopped.
    /// </summary>
    public bool Stopping
    {
        get
        {
            lock (locker)
            {
                return stopping;
            }
        }
    }

    /// <summary>
    /// Returns whether the worker thread has stopped.
    /// </summary>
    public bool Stopped
    {
        get
        {
            lock (locker)
            {
                return stopped;
            }
        }
    }

    /// <summary>
    /// Tells the worker thread to stop,typically after completing its 
    /// current work item. (The thread is *not* guaranteed to have stopped
    /// by the time this method returns.)
    /// </summary>
    public void Stop()
    {
        lock (locker)
        {
            stopping = true;
        }
    }

    /// <summary>
    /// Called by the worker thread to indicate when it has stopped.
    /// </summary>
    void SetStopped()
    {
        lock (locker)
        {
            stopped = true;
        }
    }
}
...以下形式启动线程...
public partial class Test : Form
{
    public Test()
    {
        InitializeComponent();
    }

    private ThreadWorker myThreadWorker;
    private Thread t = null;

    private void Test_Load(object sender,EventArgs e)
    {
        myThreadWorker = new ThreadWorker();

        myThreadWorker.OnProgress += new EventHandler<ProgressEventArgs>(myThreadWorker_OnProgress);
    }

    private void miStart_Click(object sender,EventArgs e)
    {
        try
        {
            listResults.Items.Insert(0,\"Set-up Thread.\");
            t = new Thread(myThreadWorker.DoSomeBackgroundWork);
            t.Name = \"My Thread\";
            t.Priority = ThreadPriority.BelowNormal;
            t.Start();

            listResults.Items.Insert(0,\"Thread started.\");

        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private void miStop_Click(object sender,\"Waiting for My Thread to terminate.\");
            listResults.Refresh();
            myThreadWorker.Stop();
            t.Join();
            listResults.Items.Insert(0,\"My Thread Finished.\");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

    private delegate void InsertToListBoxDelegate(String text);
    private void InsertToListBox(String text)
    {
        if (InvokeRequired)
            Invoke(new InsertToListBoxDelegate(InsertToListBox),new object[] { text });
        else
        {
            listResults.Items.Insert(0,\"{0}\".With(text));
            listResults.Refresh();
        }
    }

    void myThreadWorker_OnProgress(object sender,ProgressEventArgs e)
    {
        InsertToListBox(e.Text);
    }
}
问题 当我单击“停止”按钮时,它将调用...
myThreadWorker.Stop();
t.Join();
listResults.Items.Insert(0,\"My Thread Finished.\");
...我期望的是ThreadWorker继续其当前的DoLongProcess()直到完成,然后仍然通过OnProgress事件处理程序和myThreadWorker_OnProgress向UI引发事件。 但是,实际上发生的是,当引发OnProgress时,应用程序冻结在行读取中...
 Invoke(new InsertToListBoxDelegate(InsertToListBox),new object[] { text });
问题 我怎么称呼...
myThreadWorker.Stop();
t.Join();
...并且仍然响应来自后台线程的事件,直到它终止?     

解决方法

        通过调用ѭ5,您已阻止UI线程。通过调用
Control.Invoke
,您已经阻止了工作线程。
Invoke
将消息发布到UI线程的消息队列中,并等待其处理。但是,由于UI线程被阻塞,等待工作线程完成,因此它无法开始执行委托,从而使工作线程停顿。现在线程已死锁。 最大的问题是
Join
跟注。最好避免从UI线程调用
Join
。相反,请在单击停止按钮后禁用该按钮,以向用户提供停止请求已接受且正在等待的反馈。您甚至可能希望在状态栏上显示一条简单的消息,说明要清楚得多。然后,当最后一个
OnProgress
事件引发时,将表明线程已终止,您可以重置表单上的所有内容。 但是,您可能需要考虑思想上的根本转变。我认为“ 6”方法学被过度使用了。与其使用“ 6”将事件处理程序的执行编组回UI线程,还不如让UI线程使用计时器来轮询进度信息。当有新的进度信息可用时,工作人员会将其发布到某些变量或数据结构中。这有几个优点。 它打破了“ 6”强加的UI和工作线程之间的紧密耦合。 它将更新UI线程的责任放在了它应该属于的UI线程上。 UI线程可以指示更新的时间和频率。 UI消息泵不会像工作线程发起的封送处理技术那样被超限运行。 辅助线程在继续下一步之前不必等待确认已执行更新(即,UI和辅助线程上的吞吐量都更高)。     ,        只需用BeginInvoke替换Invoke。如果这是不可能的并且必须是同步的,请从本文中复制DoEvents技巧:http://www.codeproject.com/KB/cs/workerthread.aspx。 用以下循环替换t.Join(): 对于(;;) {     if(t.Join(100))//设置合适的超时时间     {        打破;     }     Application.DoEvents(); //解决死锁 }     ,        不要在UI线程上使用
Join
!这是一个很好的示例,说明人们如何破坏任何编程模型...取消后台工作人员的干净方法是安装
CancellationTokenSource
,然后向后台工作人员传递
CancellationToken
实例。如果应取消后台操作,请在已安装的实例上调用“ 17”。然后,您可以随意检查令牌的值,然后定期离开当前执行路径。我还建议您使用更高级别的异步API(任务,APM),而不是手动生成线程。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-