[英]How to terminate with Signal with MPI
這是我用C在MPI中編寫的第一個程序,該程序應該在15秒內終止,但沒有。 它甚至沒有通過if(end_now == 1)語句。 有人知道這里發生了什么嗎? 代碼簡化如下:
int end_now = 0;
void sig_handler(int signo)
{
if (signo == SIGUSR1) {
end_now = 1;
printf ( " %8d %8d\n", current_number, current_total);
}
}
int main ( int argc, char **argv ){
int id;
int count;
MPI_Init (&argc, &argv);
MPI_Comm_size (MPI_COMM_WORLD, &count);
MPI_Comm_rank (MPI_COMM_WORLD, &id);
signal(SIGUSR1, sig_handler);
while (1){
//MPI_Allreduce is called here to sum up the subtotal calculated by child processes
if (end_now == 1){
printf("here\n"); //this "here is never printed out"
break;
}
}
MPI_Finalize ();
return 0;
}
我正在使用超時--signal = USR1 15 mpirun.openmpi -np 2 ./a.out在Mac上執行代碼。 感謝任何人的幫助。
您正在向mpirun
發送信號,而不是向可執行文件發送信號。 由於mpirun
本身沒有SIGUSR1
處理程序,因此不會發生任何事情。
順便說一句,將信號與MPI程序一起使用並不是您要做的事情。 MPI程序依賴於以鎖步方式運行的多個調用,這與信號的異步和按進程性質不匹配。
Sneftel是正確的。 Gilles Gouaillardet也非常正確。 我想添加一些其他信息。
即使您將信號發送到實際程序而不是“ mpirun”,那么也可能僅將信號發送給您的所有進程之一,而不是所有進程。
是的,在MPI程序中信號不正確。 但是,即使您想使用它們,也應該首先調試獲取它們的過程以及由誰獲取的過程。
將“ printf”直接插入信號處理程序。 打印類似“ MPI進程號%d收到信號”之類的內容,然后將MPI_COMM_RANK插入此printf中。 (UPD 2018-04-27 7:31 MSK:抱歉,我沒有注意到您的代碼中已經有這樣的printf
。)(注意:我認為MPI程序中的“ printf”僅在第一個過程中允許,並且使用“ printf” “在其他進程中可能不是個好主意,但出於調試目的而已。此外,我認為直接從信號處理程序中獲取“ printf”是一個壞主意,但出於調試目的也將成為現實。)
您將確定您的進程是否能收到信號,以及哪個信號。
如果您對結果不滿意,請嘗試使用其他程序代替gtimeout。 例如,GNU Coreutils中的“超時”。 (嗯,這是Mac,我不確定GNU Coreutils是否可以從Mac使用,但我仍然認為您可以找到某些“超時”。)
然后:您沒有描述您的設置。 您的MPI程序是在不同的主機上運行還是在一個主機上運行? MPI“程序”是否真的以單獨的程序或線程的形式實現? 您使用哪個MPI實現和哪個版本? 如果您不知道MPI如何啟動您的流程,至少可以告訴我們,如何安裝MPI實施以及如何配置它。
甚至可以完全不使用任何“超時”或“ gtimeout”。 只需在一個控制台中輸入以下內容即可:
sh -c 'echo $$ > ~/pid-of-mpirun; exec ~/opt/usr/local/bin/mpirun -np 2 ./a.out'
這將在將其PID存儲到〜/ pid-of-mpirun的同時運行“ mpirun”。 並在另一個終端中並行運行(當然,您不需要完全在同一時間運行此命令):
sleep 15; kill -USR1 $(cat ~/pid-of-mpirun)
這將需要15秒,然后發送USR1來處理〜/ pid-of-mpirun中的PID。
但是所有這一切可能會將USR1發送給“ mpirun”,而不是發送給實際進程(我不確定,測試一下!)。 如何發送到實際流程? 好吧,您可以閱讀手冊頁中的“ kill”,並嘗試了解如何向整個過程組而不是僅向一個過程發送信號。
同樣,您可以將PID直接寫入C程序內的某個文件中。
例:
#include <stdio.h>
#include <unistd.h> // Mac is one of UNIX systems, so we have unistd.h
// ...
FILE *fout = fopen("~/my-pid", "w"); fprintf(fout, "%d\n", getpid); fclose(fout);
當然,您應該以某種方式確保在不同的過程中創建不同的文件。 例如,從MPI_COMM_RANK生成文件名。
還應將end_now
聲明為volatile
否則編譯器可能會優化將永遠運行的主循環。
我建議不要在信號處理程序中使用printf,因為printf是不可重入的函數,在某些平台上這可能導致程序崩潰。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.