繁体   English   中英

如何等待线程完成而不阻塞GUI?

[英]How to wait for threads to finish without blocking GUI?

我有2863个对象的数组。 我希望每1000个对象以两次“运行”通过4个线程(正在运行PC#CPU)读取数组数据。

目前,我的源代码正在对数据进行分区以纠正线程数并运行:

单次运行大小(默认)= 1000个元素
运行次数= 2
额外的螺纹行程大小= 866个元素

开始跑步[1/2]
线程为readDCMTags(i = 0,firstIndex = 0,lastIndex = 249
线程为readDCMTags(i = 1,firstIndex = 250,lastIndex = 499
线程为readDCMTags(i = 2,firstIndex = 500,lastIndex = 749
线程为readDCMTags(i = 3,firstIndex = 750,lastIndex = 999

开始跑步[2/2]
线程为readDCMTags(i = 0,firstIndex = 1000,lastIndex = 1249
线程为readDCMTags(i = 1,firstIndex = 1250,lastIndex = 1499
线程为readDCMTags(i = 2,firstIndex = 1500,lastIndex = 1749
线程为readDCMTags(i = 3,firstIndex = 1750,lastIndex = 1999
额外的线程为readDCMTags(i = 1,firstIndex = 2000,lastIndex = 2865

但是,当前的源代码会立即启动所有线程,而不是在等待RUN TO END。 当我从当前运行中加入线程时,GUI正在挂出。 该如何解决呢?

源代码是:

nrOfChunks = 2866 / 1000;
int leftOverChunk = 2866  % 1000;

for(int z = 0; z < nrOfChunks; z++)
{
    addToStatusPanel("\nStarting run [" + (z+1).ToString() + " / " + nrOfChunks.ToString() + "]");

    int indexesPerThread = 1000 / 5; #nrOfThreads
    int leftOverIndexes = 1000 % 5; #nrOfThreads

    threads = new Thread[nrOfThreads];
    threadProgress = new int[nrOfThreads];
    threadDCMRead = new int[nrOfThreads];

    for(int i = 0; i < nrOfThreads; i++)
    {
        int firstIndex = (i * indexesPerThread+z*Convert.ToInt32(chunkSizeTextBox.Text));
        int lastIndex = firstIndex + indexesPerThread - 1;

        if(i == (nrOfThreads- 1))
        {
            if(i == (nrOfThreads - 1))
            {
                lastIndex += leftOverIndexes;
            }
        }

        addToStatusPanel("readDCMTags(i=" + i.ToString() + ",firstIndex=" + firstIndex.ToString() + ", lastIndex=" + lastIndex.ToString());

        threads[i] = new Thread(() => readDCMTags(i.ToString(), firstIndex, lastIndex));
        threads[i].Name = i.ToString();

       threads[i].Start();
    }

    if(z == (nrOfChunks - 1))
    {
        int firstIndex = (nrOfChunks * Convert.ToInt32(chunkSizeTextBox.Text));
        int lastIndex = firstIndex + leftOverChunk - 1;

        addToStatusPanel("readDCMTags(i=" + z.ToString() + ",firstIndex=" + firstIndex.ToString() + ", lastIndex=" + lastIndex.ToString());
    }
}

for(int i = 0; i < nrOfThreads; i++)循环之后添加一个for(int i = 0; i < nrOfThreads; i++)线程数组的连接命令,然后再进行for(int z = 0; z < nrOfChunks; z++)下一个运行循环for(int z = 0; z < nrOfChunks; z++)将挂起GUI。

根据定义,如果您等待,则会阻塞(当前正在执行的线程会阻塞等待其他事件)。

相反,您想要的是在所有线程完成后发生某些事情。 那“所有线程都完成了”是一个事件。 因此,最好的选择是在所有线程完成后在后台线程中等待并触发事件。

如果GUI对此感兴趣,则GUI线程将需要订阅该特定事件。

编辑:伪代码(未经测试,只是想法)。

waitBg = new Thread(() => 
  {
    foreach (thread in threads)
      thread.WaitFor();

     // All threads have finished
     if (allThreadFinishedEvent != null)
        allThreadFinishedEvent();
  }
);

然后,在allThreadFinishedEvent的处理程序上,您可以执行任何操作(如果要更改UI中的某些内容,请记住将其分派到主线程,因为它将在bg线程上下文中执行)。

如何将此线程逻辑放置在后台工作器中并将后台工作的结果发送回接口。 这样,您的界面将不会在程序处理线程时被锁定。

您可以在此处找到初始化和使用backgroundworker的msdn示例。

我认为这应该是正确的前进方向。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM