2013-12-08 9 views
5

के साथ डेडलॉक मैं एमपीआई के साथ प्रयोग कर रहा हूं और भटक रहा था अगर यह कोड डेडलॉक का कारण बन सकता है।एमपीआई

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status); 
} else if (my_rank == 1) { 
    MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status); 
} 

उत्तर

9

MPI_Send कर सकते हैं या ब्लॉक नहीं कर सकते हैं। जब तक प्रेषक प्रेषक बफर का पुन: उपयोग नहीं कर लेता तब तक यह अवरुद्ध होगा। बफर को कम संचार परत पर भेजा गया है जब कुछ कार्यान्वयन कॉलर पर वापस आ जाएगा। दूसरे छोर पर MPI_Recv() मिलान करने पर कुछ अन्य कॉलर पर वापस आ जाएंगे। तो यह आपके एमपीआई कार्यान्वयन पर निर्भर करता है कि क्या यह कार्यक्रम डेडलॉक होगा या नहीं।

इस कार्यक्रम की वजह से

अलग एमपीआई कार्यान्वयन के बीच अलग-अलग ढंग से व्यवहार करता है आप इसे rewritting विचार कर सकते हैं तो वहाँ संभव गतिरोध नहीं होगा,:,

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Send (sendbuf, count, MPI_INT, 1, tag, comm); 
    MPI_Recv (recvbuf, count, MPI_INT, 1, tag, comm, &status); 
} else if (my_rank == 1) { 
    MPI_Recv (recvbuf, count, MPI_INT, 0, tag, comm, &status); 
    MPI_Send (sendbuf, count, MPI_INT, 0, tag, comm); 
} 

हमेशा ध्यान रखें कि हर MPI_Send() के लिए वहाँ एक जोड़ी MPI_Recv() होना चाहिए होना समय में दोनों "समांतर"। उदाहरण के लिए, यह डेडलॉक में समाप्त हो सकता है क्योंकि युग्मन भेजने/आरईवी कॉल समय पर गठबंधन नहीं होते हैं। वे एक दूसरे को पार:

RANK 0       RANK 1 
----------      ------- 
MPI_Send() ---   ---- MPI_Send() | 
       ---  ---     | 
       ------      | 
        --       | TIME 
       ------      | 
       ---  ---     | 
MPI_Recv() <--   ---> MPI_Recv() v 

इन प्रक्रियाओं को अन्य रास्ते पर, गतिरोध, निश्चित रूप से प्रदान की में अंत नहीं होगा, वहाँ वास्तव में रैंकों 0 और 1 एक ही संदेश वाहक डोमेन के साथ दो प्रक्रियाओं हैं कि। यदि कम्युनिकेटर com के आकार रैंक 1 (केवल 0) की अनुमति नहीं है

RANK 0       RANK 1 
----------      ------- 
MPI_Send() ------------------> MPI_Recv() | 
              | TIME 
              | 
MPI_Recv() <------------------ MPI_Send() v 

ऊपर तय कार्यक्रम विफल हो सकता है। इस तरह, if-elseelse मार्ग नहीं लेगा और इस प्रकार, MPI_Send() के लिए कोई प्रक्रिया नहीं सुनवाई जाएगी और रैंक 0 डेडलॉक होगा।

यदि आपको अपने वर्तमान संचार लेआउट का उपयोग करने की आवश्यकता है, तो आप नॉनब्लॉकिंग भेजने के लिए MPI_Isend() या MPI_Issend() का उपयोग करना पसंद कर सकते हैं, इस प्रकार डेडलॉक से परहेज कर सकते हैं।

3

@mcleod_ideafix द्वारा पोस्ट बहुत अच्छा है। मैं गैर-अवरुद्ध एमपीआई कॉल के बारे में कुछ और चीजें जोड़ना चाहता हूं।

अधिकांश एमपीआई कार्यान्वयन का तरीका यह है कि वे उपयोगकर्ता बफर से डेटा को किसी अन्य स्थान पर कॉपी करते हैं। यह कार्यान्वयन के लिए एक बफर आंतरिक हो सकता है, यह सही प्रकार के नेटवर्क पर कुछ बेहतर हो सकता है। जब उस डेटा को उपयोगकर्ता बफर से कॉपी किया जाता है और बफर को एप्लिकेशन द्वारा पुन: उपयोग किया जा सकता है, तो MPI_SEND कॉल रिटर्न। MPI_RECV मिलान करने से पहले यह कहा जा सकता है या ऐसा नहीं हो सकता है। जितना बड़ा डेटा आप भेज रहे हैं, उतना अधिक संभावना है कि आपका संदेश MPI_RECV कॉल तक अवरुद्ध हो जाएगा।

इससे बचने का सबसे अच्छा तरीका गैर-अवरुद्ध कॉल MPI_IRECV और MPI_ISEND का उपयोग करना है। इस तरह आप अपना MPI_IRECV पहले पोस्ट कर सकते हैं, फिर अपना कॉल MPI_ISEND पर बनाएं। यह संदेश आने पर अतिरिक्त प्रतियों से बचाता है (क्योंकि उन्हें पकड़ने वाला बफर MPI_IRECV के माध्यम से पहले से ही उपलब्ध है) जो चीजों को तेज़ी से बनाता है, और यह डेडलॉक स्थिति से बचाता है। तो अब आपका कोड इस तरह दिखेगा:

MPI_Comm_rank (comm, &my_rank); 
if (my_rank == 0) { 
    MPI_Irecv (recvbuf, count, MPI_INT, 1, tag, comm, &status, &requests[0]); 
    MPI_Isend (sendbuf, count, MPI_INT, 1, tag, comm, &requests[1]); 
} else if (my_rank == 1) { 
    MPI_Irecv (recvbuf, count, MPI_INT, 0, tag, comm, &status, &requests[0]); 
    MPI_Isend (sendbuf, count, MPI_INT, 0, tag, comm, &requests[1]); 
} 
MPI_Waitall(2, request, &statuses); 
0

जैसा कि mcleod_ideafix ने बताया है कि आपका कोड एक डेडलॉक हो सकता है। ये रहा: Explanation and two possible issue Solutions, one by rearranging execution order, one by async send recv calls

यहाँ async के साथ समाधान कॉल:

if (rank == 0) { 
     MPI_Isend(..., 1, tag, MPI_COMM_WORLD, &req); 
     MPI_Recv(..., 1, tag, MPI_COMM_WORLD, &status); 
     MPI_Wait(&req, &status); 
} else if (rank == 1) { 
     MPI_Recv(..., 0, tag, MPI_COMM_WORLD, &status); 
     MPI_Send(..., 0, tag, MPI_COMM_WORLD); 
} 
संबंधित मुद्दे