使用 MPI 的竞争条件

Posted

技术标签:

【中文标题】使用 MPI 的竞争条件【英文标题】:Race condition with MPI 【发布时间】:2011-12-12 07:53:01 【问题描述】:

我正在尝试使用 MPI 实现锦标赛障碍。这是我写的代码。我只写到达阶段和唤醒阶段

//Arrival phase
while(1)

    if((!strcmp(round[my_id][round_num].role,"winner"))||(!strcmp(round[my_id][round_num].role,"champion")))
    
       printf("%d is the winner of round %d\n",my_id,round_num);
       MPI_Recv(&reach_msg, sizeof(reach_msg), MPI_BYTE, round[my_id][round_num].opponent, tag, MPI_COMM_WORLD, &status);
       printf("%d received: %s\n",my_id,reach_msg);
    

    else if(!strcmp(round[my_id][round_num].role,"loser"))
    
       printf("%d is the loser of round %d\n",my_id,round_num);
       sprintf(reach_msg,"%d arrived at the barrier",my_id);
       MPI_Send(reach_msg,strlen(reach_msg+1),MPI_BYTE,round[my_id][round_num].opponent,tag,MPI_COMM_WORLD);
       MPI_Recv(wakeup_msg,sizeof(wakeup_msg),MPI_BYTE,round[my_id][round_num].opponent,tag,MPI_COMM_WORLD,&status);
       printf("%d received: %s\n",my_id,wakeup_msg);
    

if(round_num==num_rounds)
       break;
    else
       round_num++;


printf("%d is out of arrival tree\n",my_id);

//wakeup tree
      while(1)
     
       printf("%d prints: round num is: %d\n",my_id,round_num);
       if(round_num==0)
            break;
       sprintf(wakeup_msg,"wakeup msg from %d of %d",my_id,P);

       if((!strcmp(round[my_id][round_num].role,"winner"))||(!strcmp(round[my_id][round_num].role,"champion")))
       MPI_Send(wakeup_msg,strlen(wakeup_msg+1),MPI_BYTE,round[my_id][round_num].opponent,tag,MPI_COMM_WORLD);
       round_num--;
      

    MPI_Finalize();
    return 0;
   

我不明白为什么会出现竞争条件。我相信 MPI_Send 和 MPI_Recv 是阻塞函数。但是,有时它的行为并非如此

编辑:这是发生竞争条件的示例输出。如您所见,甚至在 1 发送消息之前,0 就收到了来自 1 的消息(“1 到达屏障”)。

0 是第一轮的获胜者

0 已收到:1 已到达栅栏

0 是第 2 轮的获胜者

1 是第一轮的失败者

1 发送到达消息

2 是第一轮的获胜者

2 收到:3 到达巴里

2是第2轮的失败者

2 发送到达消息

3 是第一轮的失败者

3 发送到达消息

0 已收到:2 已到达栅栏

0 发送唤醒消息

0 发送唤醒消息

收到 1:从 0 唤醒消息,在第 1 轮带有标签

收到 2:从 0 唤醒消息,在第 2 轮带有标签

2 发送唤醒消息

收到 3:从 2 唤醒消息,在第 1 轮带有标签

【问题讨论】:

通过竞争条件,我的意思是接收进程甚至在发送进程发送消息之前就接收到消息! 您的程序不太可能存在违规因果关系。您只是以这种方式看到它打印。 IIRC MPI(尽管它可能取决于实现)在进程 0 上打印所有内容,这意味着进程 1 上的“printf”实际上向它发送数据以供进程 0 打印。 @user786653:我实际上是在同一台机器上运行这段代码。我被分配了一组机器。如果我将代码分布在集群的不同机器上并运行程序会怎样? printf 语句是否仍会被发送到进程 0 进行打印? 【参考方案1】:

根据我的经验,您很可能有观察问题,而不是您的底层算法。通常这种设置中的printfs 只是乱序到达。你必须

在输出中添加时间戳 写入不同的文件,每个 MPI 进程一个 通过根据您的时间戳排序将它们重新合并在一起

【讨论】:

【参考方案2】:

对于调试 mpi 程序,打印语句通常不是一个很好的解决方案。由于打印语句需要通过网络从不同节点发送到控制台并在之前被缓存。

要调试它,您应该让每个处理器写入自己的输出文件。或者只让一个处理器打印语句,您可以通过使用 std::cerr 或以某种方式禁用 printf 的缓存来禁用缓存。

【讨论】:

【参考方案3】:

我不确定我是否完全理解您的问题...将代码输出添加到您的问题可能会有所帮助。

我可以肯定地说 MPI_Send 和 MPI_Recv 绝对是阻塞函数。您是否尝试过使用非阻塞函数(即 MPI_Isend 和 MPI_Irecv)?如果是,是否解决了您的问题?

【讨论】:

我已经添加了输出。我没有使用非阻塞发送和接收,因为我需要阻塞功能 感谢您添加输出。我同意 Jens 和 user786653 的观点,您的问题更有可能与打印订单有关,而不是与您的实施有关。

以上是关于使用 MPI 的竞争条件的主要内容,如果未能解决你的问题,请参考以下文章

如何检查是不是已应用 MPI 运行所需的所有先决条件?

如何使用 PHP 单元测试避免竞争条件

使用 __block 的竞争条件

在 Theano 中使用屏幕会话 - 竞争条件

条件竞争漏洞测试

使用 Redux 的 useEffect 竞争条件