zoukankan      html  css  js  c++  java
  • 【转】任务调度器(TaskScheduler)--解决"调用线程无法访问此对象,因为另一个线程拥有该对象"异常

    前言
    在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误(调用线程无法访问此对象,因为另一个线程拥有该对象。)这是很常见的一个错误,一不小心就会有这个现象。在WPF中,如果不是用多线程的话,例如单线程应用程序,就是说代码一路过去都在GUI线程运行,可以随意更新任何东西,包括UI对象。但是使用多线程来更新UI就可能会出现以上所说问题。
    解决方法:任务调度器(TaskScheduler)
    有很多任务调度器,在CLR Var C#中就提出了线程池任务调度器,I/O任务调度器,任务限时调度器等,调度器的职责就是负责任务的调度,调节任务执行。同步上下文任务调度器就是该方法所使用的调度器,其作用是将所有任务都调度给应用程序的GUI线程。

    1、DEMO的XAML代码:

    <Window x:Class="UpdateUIDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="130" Width="363">
        <Canvas>
            <TextBlock Width="40" Canvas.Left="38" Canvas.Top="27" Height="29" x:Name="first" Background="Black" Foreground="White"></TextBlock>
            <TextBlock Width="40" Canvas.Left="128" Canvas.Top="27" Height="29" x:Name="second" Background="Black" Foreground="White"></TextBlock>
            <TextBlock Width="40" Canvas.Left="211" Canvas.Top="27" Height="29" x:Name="Three" Background="Black" Foreground="White"></TextBlock>
            <Button Height="21" Width="50" Canvas.Left="271" Canvas.Top="58" Content="开始" Click="Button_Click"></Button>
        </Canvas>
    </Window>

    2、后台代码(抛出异常 "调用线程无法访问此对象,因为另一个线程拥有该对象。"):

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Task.Factory.StartNew(Work);
            }
    
            private void Work()
            {
                Task task = new Task((tb) => Begin(this.first), this.first);
                Task task2 = new Task((tb) => Begin(this.second), this.first);
                Task task3 = new Task((tb) => Begin(this.Three), this.first);
                task.Start();
                task.Wait();
                task2.Start();
                task2.Wait();
                task3.Start();
            }
            private void Begin(TextBlock tb)
            {
                int i=100000000;
                while (i>0)
                {
                    i--;
                }
                Random random = new Random();
                String Num = random.Next(0, 100).ToString();
                tb.Text = Num;
            }
        }

    3、改造后的正确代码:

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Task.Factory.StartNew(SchedulerWork);
            }
            private void SchedulerWork()
            {
                Task.Factory.StartNew(Begin, this.first).Wait();
                Task.Factory.StartNew(Begin, this.second).Wait();
                Task.Factory.StartNew(Begin, this.Three).Wait();
            }
    
            private void Begin(object obj)
            {
                TextBlock tb = obj as TextBlock;
                int i = 100000000;
                while (i>0)
                {
                    i--;
                }
                Random random = new Random();
                String Num = random.Next(0,100).ToString();
                Task.Factory.StartNew(() => UpdateTb(tb, Num),
                        new CancellationTokenSource().Token, TaskCreationOptions.None, _syncContextTaskScheduler).Wait();
            }
            private void UpdateTb(TextBlock tb, string text)
            {
                tb.Text = text;
            }
        }
  • 相关阅读:
    URAL 2034 : Caravans (二分最短路)
    Qt程序的字符编码方式
    Qt程序国际化
    Qt5 + msvc2015编译器 环境配置 (不安装VS)
    error: undefined reference to `Dialog::on_pushButton_clicked()'在程序代码的后台程序代码出现问题
    Qt的inherits()函数判断qt控件是否为某个类实例
    WPS使用书签跳转到指定的文档位置
    Qt error ------ 出现Error
    环境名词
    source insight 联想出Qt库函数
  • 原文地址:https://www.cnblogs.com/chriskwok/p/14246408.html
Copyright © 2011-2022 走看看