0

我试图创建一个图像处理程序,其中我只有一个带有按钮的窗口,而没有。我需要在繁重的处理功能上使用 MPI,例如傅立叶变换和高/低通。

我的问题是这个窗口是用 QT 制作的,我无法创建一个单独的窗口来调用另一个任务来完成那些繁重的处理功能。我怎样才能做到这一点?

所以,为了清楚起见,我想要的是:

A - 我的程序被初始化一次。

B - 一旦用户加载图像并单击傅立叶按钮,傅立叶计算将开始。

C - 在傅立叶计算过程中,我必须使用 MPI 进行一些并行化,将一些部分发送到其他进程,然后在傅立叶完成后将它们全部收集起来。

这可能吗?到目前为止,我所拥有的是代码的串行部分并开始使用 MPI。在第一次 glympse 中,我有多个进程运行多个窗口(例如同时打开 5 个 mspaint)。为了解决这个问题,我尝试了这个:

if ( pid == 0 )
{   
        QApplication a(argc, argv);

    MainWindow w;
        w.show();

    a.exec();
}

它创建了一个窗口。我试图通过这样做来并行化一个 for 循环:

    if ( pid == 0 )
    {
        printf("This is the master task. There are %d tasks in total", nProcs);

        for ( i = 1; i < nProcs; i++ )
        {
            MPI_Send( &complexPixel[i*width/nProcs][0], width*height/nProcs,  MPI_DOUBLE, i, tag, MPI_COMM_WORLD );
                MPI_Send( &H,   width*height, MPI_DOUBLE, i, tag, MPI_COMM_WORLD );
        }
    }
    else
    {
            printf("This is a slave task. PID = %d\n", pid);
            MPI_Recv( &complexPixel, width*height/nProcs, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD, &statusMPI );
            MPI_Recv( &H, width*height,  MPI_DOUBLE, 0, tag, MPI_COMM_WORLD, &statusMPI );
        }
    }

    DoSomeWork();

    if ( pid != 0 )
    {
        MPI_Send( &T, width*height/nProcs, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD );
        printf("Slave work finished.\n");
    }
    else
    {
        for ( i = 1; i < nProcs; i++ )
                MPI_Recv( &T[i*width/nProcs][0], width*height/nProcs, MPI_DOUBLE, i, tag, MPI_COMM_WORLD, &statusMPI );
            printf("Master work finished.\n");
    }

现在我被第一个 MPI_Send 卡住了,因为我命令主任务执行整个窗口,似乎这是唯一能够处理它的进程。

感谢您的时间!希望我能让这个工作!

4

2 回答 2

1

我很乐意为 Qt 和 MPI 使用单个进程:使用线程将用户界面行为与 MPI 和计算分开 - 这样您就有了响应式用户界面。但这并非没有挑战。

哪个线程做什么?

  • 有据可查的需要所有 GUI 工作都在“主线程”中 - 这对于 Linux 实际上不是必需的,但对于 OS/X (previous S/O answer)是必需的。
  • 这与 MPI 冲突 - 许多 MPI 要么不支持,要么需要专门编译以启用多线程。阅读 MPI_Init_thread 的手册页,因为这可以帮助您确定线程支持的级别。

碰巧的是,最常见的 MPI,Open MPI,在 MPI_THREAD_FUNNELED 和 MPI_THREAD_SINGLE 之间没有区别(之前的讨论) ——这意味着如果你只使用非 GUI 线程进行 MPI,你会没事的。

图书馆

如果您对应用程序中的每个进程使用相同的二进制文件,那么如果您计划使用集群,则必须确保库依赖项在集群的节点上可用 - 而不仅仅是在其中的节点(登录节点)图形用户界面正在运行。在实践中这可能很痛苦:Qt 引入了很多 X 依赖项,除非您只使用 QtCore 并且拥有非 GUI 应用程序。

开放式 MPI(和许多其他 MPI)允许您使用多个不同的二进制文件 - 因此您可以为一个进程(在 GUI 节点上)运行与 GUI 相关的代码的一个版本,而其他版本可以是单线程的非 GUI QtCore 链接应用程序并具有较少的库依赖项。

于 2013-06-20T21:06:34.227 回答
0

在我看来,您绝对应该尝试做的是将显示 GUI 的二进制文件与进行计算的二进制文件完全分开。我会尝试以下。

创建一个实现 GUI 的程序。该程序必须分配共享内存(或在 shm 分区中创建文件)。创建第二个使用 MPI 实现计算的程序;该程序的主进程必须与 GUI 程序在同一个节点上运行,并访问同一个共享内存(或文件)。其他进程一直等到它们从主进程获得集体通信(例如 aMPI_Bcast或)。MPI_Gather

主进程依次等待直到 GUI 程序触发一个信号,该信号在用户输入被收集并且共享缓冲区(或文件)被填满后立即发出。此时主进程发出集体通信,并开始通过 MPI 进行计算。

一旦这个计算结束,主进程收集输出,使用共享内存(或文件)将它返回给 GUI 程序,或者将它写入一个输出文件,或者你必须用它做的任何事情,并告诉 GUI 程序计算是通过另一个信号完成的,或者如果 GUI 程序正在轮询,则仍然使用共享内存(这很容易用 Qt.

最后,请记住,使用 MPI,您不能像使用 OpenMP 那样“并行化循环”:您必须设计整个流程以及这些流程之间的通信。并且避免混合用户界面(无论是 Qt、curses、CLI 等)和计算允许将两个非常不同的任务分离给程序员并使用不同的编译器标志编译它们(例如,您可能想要编译计算部分与 -O3 和 GUI 与 -O2 或 -Os)。

于 2013-06-17T08:39:49.057 回答