【问题标题】:C# WFA - delegate time consuming work to another threadC# WFA - 将耗时的工作委托给另一个线程
【发布时间】:2019-01-08 23:02:01
【问题描述】:

我想在 C# (WFA) 中创建一些机制,允许我在运行中向一个特定的单独线程添加一些函数。

public class MyClass
{
    private Thread specialThread = new Thread();
    MyClass()
    {
        regularMethod();
        specialThread.AddNextJob( veryLongTimeConsumingMethod() );
        //....
        anotherUseMethod();
    }
    private void veryLongTimeConsumingMethod()
    {
        //...time consuming database, logic, etc...
        this.UIThread(delegate ()
        {
            control1.Items = updatedItems;
        });
    }

    private void anotherUseMethod()
    {
        //...another method wants to do a long job
        specialThread.AddNextJob(veryLongTimeConsumingMethod());
    }
}

在所有“工作”完成后,我希望“特殊线程”处于“待机”状态(等待另一个“工作”)。我需要按顺序完成所有“工作”。 有什么通用的方法可以实现吗?

【问题讨论】:

    标签: c# multithreading winforms delegates task


    【解决方案1】:

    我不久前写过这样的东西。现在你可能会使用 async await 来让东西在后台线程上运行。但这是我写的一个快速任务队列。

    public class TaskQueue
    {
        public Queue<Task> CurrentTasks { get; private set; }
        public bool TaskQueueRunning { get; private set; }
    
        public TaskQueue()
        {
            CurrentTasks = new Queue<Task>();
            TaskQueueRunning = false;
        }
    
        public void AddTask(Task task)
        {
            CurrentTasks.Enqueue(task);
            ProcessTasks();
        }
    
        private void ProcessTasks()
        {
            if (!TaskQueueRunning)
            {
                TaskQueueRunning = true;
                ProcessIndividualTask();
            }
        }
    
        private void ProcessIndividualTask()
        {
            if (CurrentTasks.Count > 0)
            {
                TaskItem currenttask = CurrentTasks.Dequeue();
                currenttask.CurrentTask.ContinueWith(x => ProcessIndividualTask());
                currenttask.CurrentTask.Start();
            }
            else
            {
                TaskQueueRunning = false;
            }
        }
    }
    

    你在你的主窗体上实例化它:

    private TaskQueue backgroundtasks = new TaskQueue();
    

    然后,当您想在后台线程上执行方法时,您将其包装在任务中。例如

    Task newtask = new Task(() => MyMethodCall());
    backgroundtasks.AddTask(newtask);
    

    或者如果你想内联整个东西:

    backgroundtasks.AddTask(new Task(() => MyMethodCall()));
    

    如果任务队列中没有项目,则队列不会运行,如果添加项目,队列将运行。如果您在第一个任务完成时添加多个项目,它将ContinueWith 下一个任务。任务将始终按顺序运行,因为底层类型是队列,只有在当前任务完成后才会运行下一个任务。

    这样做的一个限制是您的任务无法返回结果。不过,您可以设置一个任务来写入变量。例如

    Task newtask = new Task(() => {
                                      myvar = MyMethodCall();
                                  });
    backgroundtasks.AddTask(newtask);
    

    这假设您的主窗体上有一个名为 myvar 的属性/变量。但是要小心这一点,因为如果您从不同的任务多次写入同一个变量,您将无法预测任何时候该值是什么 - 特别是如果您从不同的线程访问它。说到跨线程——这里没有防护,所以要特别小心。

    建议您研究 Async 和 Await,因为您可能会发现它们更适合您想做的事情。

    【讨论】:

    • 投反对票的人愿意评论为什么这个答案被投反对票吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多