C#WFA-将耗时的工作委托给另一个线程

时间:2018-08-01 11:31:50

标签: c# multithreading winforms delegates task

我想在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());
    }
}

在所有“工作”完成后,我希望“ specialThread”处于“待命”状态(等待另一个“工作”)。我需要做所有的“工作”,以便添加它们。 有什么通用的方法可以做到这一点吗?

1 个答案:

答案 0 :(得分:-1)

我前一段时间写了这样的东西。如今,您可能会使用async等待来使内容在后台线程上运行。但是,这是我编写的快速TaskQueue。

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的主窗体上具有属性/变量。但是要特别小心,因为如果您从不同的任务多次写入相同的变量,则您将无法预测任何时间的值,尤其是当您从不同的线程访问它时。谈论跨线程-这里没有防护,所以要特别小心。

建议您研究“异步”和“等待”,因为它们可能更适合您的工作。