【WPF】多线程Demo

该程序框架展示了一个WPF窗口,包含用于启动和停止任务的按钮以及显示任务状态的文本框。任务管理器类`ManagerJob`负责创建和管理多个`TaskJob`,每个任务有特定的执行时间和动作。当任务完成时,`ManagerJob`会更新界面显示。点击‘Start’开始任务,‘Stop’则停止任务执行。通过调整代码,可以实现每个任务仅执行一次并确保成功完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

43638b35e86f4b47b72155b4d6077b2f.png

程序框架

主界面:

baf1d4a8d301f69a1ea66745e19232e3.png

主窗体xaml:

<Grid Background="#FFDEDED4">
        <TextBox x:Name="txtCountThreads" HorizontalAlignment="Left" Height="45" Margin="31,23,0,0" Text="7" TextWrapping="Wrap" VerticalAlignment="Top" Width="112" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="16" FontWeight="Bold"/>
        <Button x:Name="btnStart" Content="Start" Click="btnStart_Click" HorizontalAlignment="Left" Height="45" Margin="531,23,0,0" VerticalAlignment="Top" Width="112" FontSize="16" FontWeight="Bold"/>
        <Button x:Name="btnStop" Content="Stop" Click="btnStop_Click" HorizontalAlignment="Left" Height="45" Margin="656,23,0,0" VerticalAlignment="Top" Width="112" FontSize="16" FontWeight="Bold" Foreground="#FFE65429"/>
        <ScrollViewer x:Name="scrollView" VerticalScrollBarVisibility="Auto" 
                 Height="459" 
                 Width="736" 
                 Margin="0,93,0,0"
                 HorizontalScrollBarVisibility="Disabled">
            <TextBlock x:Name="txtPayload"  Text=""  Background="White"/>
        </ScrollViewer>
    </Grid>

主窗体交互逻辑:

public partial class MainWindow : Window
    {
        ManagerJob managerJob;
       
        public MainWindow()
        {
            InitializeComponent();
        }
        //更新数据显示
        public void AddMessageToPayload()
        {
            this.Dispatcher.Invoke(() =>
            {
                /// using '=' Instead of '+=' to save memory
                this.txtPayload.Text += ManagerJob.payloadString.ToString();//显示有效负载信息
                this.scrollView.ScrollToEnd();
                if (ManagerJob.payloadString.ToString().Contains("Manager task finished work"))
                {
                    btnStart.IsEnabled = true;
                }
            });
        }


        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            string countStr = txtCountThreads.Text;
            try
            {
                int count = Int32.Parse(countStr);//任务数
                if(count <= 0 )
                {
                    MessageBox.Show("Enter number > 0");
                }
                else
                {
                    managerJob = new ManagerJob(count);//
                    // Add reference to external method to update data
                    ManagerJob.addMessage += AddMessageToPayload; //添加对外部方法的引用以更新数据
                    managerJob.Start();
                    btnStart.IsEnabled = false;
                }
            }
            catch (FormatException)
            {
                MessageBox.Show("Can't Parsed '{0}'", countStr);
            }
        }


        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            this.managerJob.Stop();
        }
    }

任务类 TaskJob.cs:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace ConsoleApp1.app.classes
{
    class TaskJob
    {
        private int timeSpan;//时间 毫秒
        private Task task;//任务
        //任务构造函数:动作,时间
        public TaskJob(Action action, int timeSpan)
        {
            this.task = new Task(action);
            this.TimeSpan = timeSpan;


        }
        //任务成功完成信息
        public string IsCompletedSuccessfully { get {
                string res = this.task.IsCompletedSuccessfully ? "" : "NOT";
                return string.Format("task {0,3} completed {1} successfully", this.task.Id, res);
            }
        }
        //任务执行信息
        public string TotalResult
        {
            get
            {
                return string.Format("{0,3} times in {1,4} milliseconds total {2,4} miliseconds", this.Counter, this.TimeSpan, TotalTime);
            }
        }
        //开启任务并返回任务ID
        public int Start()
        {
            this.task.Start();


            return this.task.Id;
        }


        public int TimeSpan { get => timeSpan; set => timeSpan = value; }//任务执行时间
        public int Counter { get; set; } = 0;  //任务执行次数
        public int TotalTime { get => this.TimeSpan * this.Counter; } //总时间 
    }
}

任务管理者类ManagerJob.cs:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace ConsoleApp1.app.classes
{
    delegate void AddMessageDelegate();//声明添加消息委托


    class ManagerJob
    {
        const int TIME_SPAN_MIN = 10;
        const int TIME_SPAN_MAX = 1000;
        const int TIME_TO_SUPPLIER_DATA = 1000; //添加信息数据时间


        public static AddMessageDelegate addMessage; //声明一个事件,委托类型
        private static EventWaitHandle waitHandleStartJob = new AutoResetEvent(true);  //等待开始事件  true设置初始状态为有信号;False设置初始状态为无信号。
        private static EventWaitHandle waitHandleUpdateMessage = new AutoResetEvent(true);//等待更新消息事件
        private Task manager;//管理者任务
        private static Hashtable listJobs = new Hashtable();//哈希表:任务列表
        public static StringBuilder payloadString = new StringBuilder();//有效载荷字符串
        private static Queue<string> buffer = new Queue<string>();//字符串缓存队列:信息
        private static bool trueToDO = true;//执行任务标记
        private static int CountJobs { set; get; }//任务数


        public ManagerJob(int countJobs)//构造函数:任务数
        {
            CountJobs = countJobs;
            manager = new Task(ManagerTask);//管理者任务
        }
        /// <summary>
        /// ManagerTask method to main task named ManagerTask
        /// 1. Create work tasks. 
        /// 2. Read from queue buffer and run external code (addMessage()) to update data.
        /// 3. Waiting for the end of work all tasks.
        /// </summary>
        private static void ManagerTask()
        {
            buffer.Enqueue("Manager task is started.");//消息队列
            Random random = new Random();
            for (int i = 0; i < CountJobs; i++)//创建带执行时间的任务,开启任务并加入任务列表。
            {
                int timeSpan = random.Next(TIME_SPAN_MIN, TIME_SPAN_MAX);
                TaskJob job = new TaskJob(ToDoJob, timeSpan);//实例化TaskJob
                listJobs.Add(job.Start(), job);//开启任务并加入任务列表:  任务id,TaskJob
            }
            //任务执行过程中,更新显示线程状态
            while (CountJobs > 0)
            {
                Thread.Sleep(TIME_TO_SUPPLIER_DATA);//等待更新数据间隔
                getData();//将消息队列中的信息显示到界面


            }
            //任务都执行完成后
            foreach (DictionaryEntry pair in listJobs)
            {
                TaskJob job = (TaskJob)pair.Value;
                buffer.Enqueue(string.Format("{0} {1}", job.IsCompletedSuccessfully, job.TotalResult));
            }
            buffer.Enqueue("Manager task finished work");
            getData();//最后输出 任务完成信息        
        }
        //显示buffer信息
        private static void getData()
        {
            while (buffer.Count > 0)
            {
                payloadString.AppendFormat("{0}{1}", buffer.Dequeue(), Environment.NewLine);//取出缓存信息
            }
            addMessage();//触发添加消息事件
            payloadString.Clear();
        }
        /// <summary>
        /// ToDoJob method to  tasks TaskJob
        /// 1. To start job waiting to find job in class 'waitHandleStartJob.WaitOne();' first task(thread) into 
        /// 2. job(sleep)
        /// 3. white to update data 'waitHandleUpdateMessage.WaitOne();'
        /// </summary>
        private static void ToDoJob()//任务动作
        {
            do
            {
                //第一个任务进入代码,其他任务等待 First task enter to code. The others are waiting.
                waitHandleStartJob.WaitOne();//两个线程共享相同的AutoResetEvent对象,线程可以通过调用AutoResetEvent对象的WaitOne()方法进入等待状态,然后另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。
                TaskJob jobStarted = null;
                if (listJobs.ContainsKey(Task.CurrentId))
                {
                    jobStarted = (TaskJob)listJobs[Task.CurrentId];//获取开启的TaskJob对象
                }
                else
                {
                    break;
                }
                jobStarted.Counter++; //在timeSpan*n()时间内,切换执行当前Task的次数。
                // 第一个任务切换waitHandleStartJob进入下一个线程。  First task switch waitHandleStartJob to enter next thread.
                waitHandleStartJob.Set();//另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。


                // Job (all tasks sleep time is defined in the constructor) 
                Thread.Sleep(jobStarted.TimeSpan);


                // 最先唤醒的任务进入编码Task which woke up first enter to code 
                waitHandleUpdateMessage.WaitOne();//线程可以通过调用AutoResetEvent对象的WaitOne()方法进入等待状态
                TaskJob jobFinish = null;
                if (listJobs.ContainsKey(Task.CurrentId))
                {
                    jobFinish = (TaskJob)listJobs[Task.CurrentId];
                }
                else
                {
                    break;
                }


                DateTime date = DateTime.Now;
                buffer.Enqueue( string.Format("job number {0,3} completed job in {1:HH:mm:ss.fff} after {2,4} miliseconds (total {3,8}).", Task.CurrentId, date, jobFinish.TimeSpan, jobFinish.TotalTime));


                //任务切换到下一个任务的waitHandleUpdateMessage。 Task switch waitHandleUpdateMessage to next task.
                waitHandleUpdateMessage.Set();//另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。


                //CountJobs--; //正在执行的总任务数--      
               //return;    
                //取消以下注释,每个任务只执行一次。执行完毕后需手动停止管理者任务。
                //增加以下代码 
                //CountJobs--; //正在执行的总任务数--      
                //while (trueToDO)
                //{
                //    Thread.Sleep(100);
                //    //判断所有任务执行完毕,自动结束管理者任务
                //    if (CountJobs == 0)
                //    {
                //        trueToDO = false;
                //    }
                //}
            } while (trueToDO);
            CountJobs--; //正在执行的总任务数--
        }
        public void Start()
        {
            this.manager.Start();
        }
        public void Stop()
        {
            // boolen var trueToDO = false  => means stop infinite loop for TaskJob tasks
            trueToDO = false;
        }
    }
}

单击“start”之后,单击“stop”执行结果:

2f303b4a12810d04bfba397a7106f847.png

取消注释后,单击“start”执行结果:执行一次任务后自动停止。有失败的任务。

// 取消以下注释,每个任务只执行一次。执行完毕后需手动停止管理者任务。
                //增加以下代码
                CountJobs--; //正在执行的总任务数--      
                while (trueToDO)
                {
                    Thread.Sleep(10);//100 改成1000   所有任务都失败. 改成10任务都成功。
                    //判断所有任务执行完毕,自动结束管理者任务
                    if (CountJobs == 0)
                    {
                        trueToDO = false;
                    }
                }

d3ad3f31dacbe5b400fed652a46ae1fb.png

c3d67f14a337db275c62cb95a756523d.png

ccfe520143e7e434bcc338cbe3da0674.png

68047cf3ebbb02fe9b996427aa172c69.png

修改为如下之后,每个任务执行一次,都执行成功,速度快:

29d4fa4b3f803c150abbfb69c5e5e817.png

The End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值