.net NET Windows窗体应用程序的多线程控制

.net NET Windows窗体应用程序的多线程控制,.net,winforms,multithreading,.net,Winforms,Multithreading,我正在使用开发.NET Windows窗体应用程序 在这个应用程序中,我需要四个后台线程来进行底层数据传输。当所有四个线程完成时,将再次使用这四个线程开始另一轮四个底层数据传输 表单UI需要始终具有响应性。我的问题是:如何控制四个线程的运行?比如:我怎么知道所有的线程都完成了?使用易失性全局计数器?要回答有关使用特别是四线程的问题,下面是使用BackgroundWorker的快速草图。这里的想法是设置四个任务,跟踪正在运行的任务的数量,并在所有任务完成后重新启动。有关volatile vs in

我正在使用开发.NET Windows窗体应用程序

在这个应用程序中,我需要四个后台线程来进行底层数据传输。当所有四个线程完成时,将再次使用这四个线程开始另一轮四个底层数据传输


表单UI需要始终具有响应性。我的问题是:如何控制四个线程的运行?比如:我怎么知道所有的线程都完成了?使用易失性全局计数器?

要回答有关使用特别是四线程的问题,下面是使用BackgroundWorker的快速草图。这里的想法是设置四个任务,跟踪正在运行的任务的数量,并在所有任务完成后重新启动。有关volatile vs interlocked的讨论,请参阅堆栈溢出问题

这将满足您的要求(四个线程,响应用户界面),但没有错误处理,可能还有其他问题。有没有可能一个后台工作人员会挂起电话(也许你的“数据传输”出了问题),在这种情况下,你会陷入糟糕的状态

public partial class Form1 : Form  {
    private int workersRunning = 0;
    private List<BackgroundWorker> workers = new List<BackgroundWorker>();

    public Form1()  {
        InitializeComponent();
        for (int i = 0; i < 4; i++)  {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(this.worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.worker_RunWorkerCompleted);
            workers.Add(worker);
        }
    }

    private void button1_Click(object sender, EventArgs e) {
        this.StartWork();
    }

    private void StartWork() {
        workers.ForEach(worker => worker.RunWorkerAsync());
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
        Interlocked.Decrement(ref workersRunning);
        Console.WriteLine("Worker reported completion from thread id " + e.Result);
        if(this.workersRunning == 0) {
            Console.WriteLine("All workers are done. Start again");
            this.StartWork();
        }  else  {
            Console.WriteLine(this.workersRunning + " workers are still running.");
        }
    }

    void worker_DoWork(object sender, DoWorkEventArgs e) {
        Interlocked.Increment(ref workersRunning);
        int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Doing work on thread #" + threadId);

        Thread.Sleep(new Random().Next(2000, 5000));

        e.Result = "Work done on thread id " + threadId;
    }
}
公共部分类表单1:表单{
私有int-workersRunning=0;
私有列表工作者=新列表();
公共表格1(){
初始化组件();
对于(int i=0;i<4;i++){
BackgroundWorker工人=新的BackgroundWorker();
worker.DoWork+=新的doworkereventhandler(this.worker\u DoWork);
worker.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(this.worker\u RunWorkerCompleted);
工人。添加(工人);
}
}
私有无效按钮1\u单击(对象发送者,事件参数e){
这个。StartWork();
}
私人网络{
worker.ForEach(worker=>worker.RunWorkerAsync());
}
void worker\u RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e){
联锁减量(参考工作人员运行);
Console.WriteLine(“工作线程id报告的完成情况”+e.Result);
if(this.workersRunning==0){
Console.WriteLine(“所有工作人员已完成。重新开始”);
这个。StartWork();
}否则{
Console.WriteLine(this.workersRunning+“workers仍在运行”);
}
}
无效工作线程(对象发送器,工作线程目标){
联锁增量(参考工作人员运行);
int threadId=System.Threading.Thread.CurrentThread.ManagedThreadId;
Console.WriteLine(“在线程上工作”#“+threadId);
Sleep(newrandom().Next(20005000));
e、 结果=“在线程id上完成的工作”+线程id;
}
}

要回答您关于使用特别是四个线程的问题,下面是一个使用BackgroundWorker的快速草图。这里的想法是设置四个任务,跟踪正在运行的任务的数量,并在所有任务完成后重新启动。有关volatile vs interlocked的讨论,请参阅堆栈溢出问题

这将满足您的要求(四个线程,响应用户界面),但没有错误处理,可能还有其他问题。有没有可能一个后台工作人员会挂起电话(也许你的“数据传输”出了问题),在这种情况下,你会陷入糟糕的状态

public partial class Form1 : Form  {
    private int workersRunning = 0;
    private List<BackgroundWorker> workers = new List<BackgroundWorker>();

    public Form1()  {
        InitializeComponent();
        for (int i = 0; i < 4; i++)  {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(this.worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.worker_RunWorkerCompleted);
            workers.Add(worker);
        }
    }

    private void button1_Click(object sender, EventArgs e) {
        this.StartWork();
    }

    private void StartWork() {
        workers.ForEach(worker => worker.RunWorkerAsync());
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){
        Interlocked.Decrement(ref workersRunning);
        Console.WriteLine("Worker reported completion from thread id " + e.Result);
        if(this.workersRunning == 0) {
            Console.WriteLine("All workers are done. Start again");
            this.StartWork();
        }  else  {
            Console.WriteLine(this.workersRunning + " workers are still running.");
        }
    }

    void worker_DoWork(object sender, DoWorkEventArgs e) {
        Interlocked.Increment(ref workersRunning);
        int threadId = System.Threading.Thread.CurrentThread.ManagedThreadId;
        Console.WriteLine("Doing work on thread #" + threadId);

        Thread.Sleep(new Random().Next(2000, 5000));

        e.Result = "Work done on thread id " + threadId;
    }
}
公共部分类表单1:表单{
私有int-workersRunning=0;
私有列表工作者=新列表();
公共表格1(){
初始化组件();
对于(int i=0;i<4;i++){
BackgroundWorker工人=新的BackgroundWorker();
worker.DoWork+=新的doworkereventhandler(this.worker\u DoWork);
worker.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(this.worker\u RunWorkerCompleted);
工人。添加(工人);
}
}
私有无效按钮1\u单击(对象发送者,事件参数e){
这个。StartWork();
}
私人网络{
worker.ForEach(worker=>worker.RunWorkerAsync());
}
void worker\u RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e){
联锁减量(参考工作人员运行);
Console.WriteLine(“工作线程id报告的完成情况”+e.Result);
if(this.workersRunning==0){
Console.WriteLine(“所有工作人员已完成。重新开始”);
这个。StartWork();
}否则{
Console.WriteLine(this.workersRunning+“workers仍在运行”);
}
}
无效工作线程(对象发送器,工作线程目标){
联锁增量(参考工作人员运行);
int threadId=System.Threading.Thread.CurrentThread.ManagedThreadId;
Console.WriteLine(“在线程上工作”#“+threadId);
Sleep(newrandom().Next(20005000));
e、 结果=“在线程id上完成的工作”+线程id;
}
}

.NET4善意地提供了类和相关的统一高级异步API。因此,您可以安全地从基于BackgroundWorker的设计切换到基于任务的设计,然后您将看到使用
Task.Factory.continuewhalll
等待所有任务完成是多么容易


请参阅。

.NET4提供了类和相关的统一高级异步API。因此,您可以安全地从基于BackgroundWorker的设计切换到基于任务的设计,然后您将看到使用
Task.Factory.continuewhalll
等待所有任务完成是多么容易


请参阅。

四个后台线程是否将结果返回到UI?四个后台线程是否将结果返回到UI?谢谢Lex,我将检查任务工厂谢谢Lex,我将检查任务工厂请随意将此作为答案如果这有帮助Jeffrey,我刚刚发现我可以在Stackoverflow上标记答案。谢谢如果这对Jeffrey有帮助的话,请随意回答这个问题。我刚刚发现我可以在Stackoverflow上标记答案。谢谢