首页 > 解决方案 > C# WFA - 将耗时的工作委托给另一个线程

问题描述

我想在 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#multithreadingwinformsdelegatestask

解决方案


我前一阵子写过这样的东西。现在你可能会使用 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,因为您可能会发现它们更适合您想要做的事情。


推荐阅读