将不同的线程方法结合到 Windows 窗体应用程序
我正在开发一个 Windows 窗体应用程序,旨在执行实时图像处理。用户界面是一个关键元素,我想使用多线程来独立于 UI 线程执行图像处理任务。不仅如此,由于计算的强度,我希望在多个线程上执行图像处理。
我设法做到这一点的一种方法是使用 ThreadStart 委托在多个线程上进行处理。这工作得很好,但我明确创建了每个线程。我研究过的另一种方法是使用 openMP 在多个线程上执行处理任务。 OpenMP 似乎是一种更简单的方法,因为它自动将处理分配给所有可用线程。当程序在不同计算机上运行并且每台计算机上具有不同数量的内核时,这将特别有用。然而,我发现 openMP 方法缺乏用户响应能力,我得出的结论是,这是由于计算也是在 UI 线程上完成的。
因此,我尝试结合这两种方法,我使用 threadstart 启动一个新线程,从中调用一个函数,该函数使用 openMP 执行图像处理以并行化 for 循环。然而,当我这样做时,程序不会使用所有可用的线程(似乎只使用 8 个线程中的 2 个或 3 个)。
因此我的问题如下:尝试以这两种不同的方式进行多线程处理是否是不好的做法?有没有一种方法可以成功实现方法组合,以便在所有可用线程上进行图像处理,但让 UI 线程处理用户输入?或者也许有一个仅使用上述方法之一的更简单的实现?我意识到我可能可以使用 threadstart 动态创建线程,但这似乎是一种比我可以使用 openMP 更复杂的方法。
这是一些伪代码,显示了我想要做的事情(注意:ProcessedData 和 ImageData 是像素数据的无符号字符数组):
//this sets up a new thread when called for in the form
public: static void ThreadProc()
{
ProcessedData=compute(ImageData); //this is the image processing, there are other variable as well as ImageData
};
//this computes the processed image when the user moves a label/node
private: void labelnode_MouseMove( Object^ /*sender*/, System::Windows::Forms::MouseEventArgs^ e ) {
//if not being moved or left mouse button not used, exit
if (!bMoving || e->Button != System::Windows::Forms::MouseButtons::Left)
{
return;
};
Thread^ oThread = gcnew Thread( gcnew ThreadStart( &Form1::ThreadProc ) );
oThread->Start(); //launch new thread to do calculations for image processing
};
计算函数包含以下并行循环:
#define CHUNKSIZE 1
#pragma omp parallel
{
#pragma omp for schedule(dynamic, CHUNKSIZE)
for (i=0;i<numberofrows;i++)
{
//Process all of the pixels in the given row putting results in the processed data array.
};
};
更新:实际上,事实证明调试工具阻止了该应用程序。在外部运行 exe 可以正常工作。但是,现在我遇到了内存泄漏,在该过程重复足够多次后会导致崩溃。我确信在与 openMP 并行之前没有内存泄漏,所以我想知道线程的连续打开和关闭是否留下了一些剩余内存。有什么想法吗?
I'm developing a windows form application that aims at performing real time image manipulation. User interface is a key element and I want to use multithreading to perform image processing tasks separate from the UI thread. Not only this, but due to the intesity of the calculations I wish to perform the image processing on multiple threads.
One way I have managed to do this is by using the ThreadStart delegate to do the processing on multiple threads. This works quite well but I am explicitly creating each thread. Another approach I have looked at is using openMP to perform processing tasks on multiple threads. OpenMP seems to be a much simpler approach since it automatically assigns the processing to all available threads. This would be paricularly useful where the program is run on different computers with different numbers of cores on each. However I find that the user responsiveness is lacking with the openMP approach and I have come to the conclusion that this is due to calculations being done on the UI thread as well.
I hence tried to combine the two approaches, I start a new thread using threadstart from which I call a function that performs the image processing using openMP to parallelize a for loop. However when I do this the program does not use all of the threads available to it (it seems to only use 2 or 3 out of 8).
Hence my questions are the following: Would it be bad practice to try and do the multithreading in these two different ways? Is there a way to successfully implement the combination of approaches such that it does the image processing on all available threads but leaves the UI thread to handle user input? Or perhaps there is a simpler implementation using only one of the above approaches? I realise that I could probably dynamically create threads using threadstart but this seems like a more complicated approach then if I could use openMP instead.
Here is some pseudocode showing what I want to do (note: ProcessedData and ImageData are unsigned char arrays of pixel data):
//this sets up a new thread when called for in the form
public: static void ThreadProc()
{
ProcessedData=compute(ImageData); //this is the image processing, there are other variable as well as ImageData
};
//this computes the processed image when the user moves a label/node
private: void labelnode_MouseMove( Object^ /*sender*/, System::Windows::Forms::MouseEventArgs^ e ) {
//if not being moved or left mouse button not used, exit
if (!bMoving || e->Button != System::Windows::Forms::MouseButtons::Left)
{
return;
};
Thread^ oThread = gcnew Thread( gcnew ThreadStart( &Form1::ThreadProc ) );
oThread->Start(); //launch new thread to do calculations for image processing
};
The compute function contains the following parallel loop:
#define CHUNKSIZE 1
#pragma omp parallel
{
#pragma omp for schedule(dynamic, CHUNKSIZE)
for (i=0;i<numberofrows;i++)
{
//Process all of the pixels in the given row putting results in the processed data array.
};
};
UPDATE: Actually it turns out that the debugging tools were preventing the full performance of the application. Running the exe externally works as it should. However, now I have a memory leak which causes a crash after the process has been repeated enough times. I'm sure there was no memory leak before I parallelised with openMP so I'm wondering if there is some residual memory left from the continuous opening and closing of threads. Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的方法是正确的:建议的模式是保留主线程以提高 UI 响应能力,并为计算密集型作业启动一个单独的线程,使用 OpenMP(或任何其他并行框架)并行处理此作业。
为什么它不以这种方式使用所有硬件线程/核心是一个单独的问题。这可能是由于负载不平衡,或某些同步问题,或计算的重要串行部分,或所有线程的工作量始终不足。
Your approach is right: it's a recommended pattern to keep the main thread for UI responsiveness and start a separate thread for compute-intensive job, using OpenMP (or any other parallel framework) to process this job in parallel.
Why it does not use all HW threads/cores this way is a separate question. It might be due to load imbalance, or some synchronization issues, or significant serial portions of computation, or the amount of work being insufficient for all threads all the time.