On May 24, 2010, at 19:42 , Gijsbert Wiesenekker wrote:

> My MPI program consists of a number of processes that send 0 or more messages 
> (using MPI_Isend) to 0 or more other processes. The processes check 
> periodically if messages are available to be processed. It was running fine 
> until I increased the message size, and I got deadlock problems. Googling 
> learned I was running into a classic deadlock problem if (see for example 
> http://www.cs.ucsb.edu/~hnielsen/cs140/mpi-deadlocks.html). The workarounds 
> suggested like changing the order of MPI_Send and MPI_Recv do not work in my 
> case, as it could be that one processor does not send any message at all to 
> the other processes, so MPI_Recv would wait indefinitely.
> Any suggestions on how to avoid deadlock in this case?
> 
> Thanks,
> Gijsbert
> 

An approach that seems to work in my case is the following:
I was using separate message-tags for 'update_message' and 'no_more_messages'. 
All these were sent asynchronously. The receive code in pseudo-code looked like:
--
if (probe_for_update_message() == FALSE)
{
        if (probe_for_no_more_messages() == TRUE)
        {
                //we are done
        }
        else
        {
                //do some work
        }
}
else
{
        //process update message
}
--
The problem with this receive code was that in between the 
probe_for_update_message() and the probe_for_no_more_messages() a processor 
could send several update messages, followed by 'no_more_messages', so I still 
needed to check for any pending update messages after a 
probe_for_no_more_messages(), which complicated handling deadlock. So I first 
created a special update message that signals 'no_more_messages', which 
simplified the receive code to:
--
//probe_for_update_message() returns INVALID if no more messages, TRUE if 
message, FALSE if not
if ((result = probe_for_update_message()) == INVALID)
{
        //we are done
}
else if (result == TRUE)
{
        //process update message
}
else //result == FALSE
{
        //do some work
}
--
Now to deal with the deadlock I first created a function recv_update_message() 
that probes for update messages and pushes them onto a FIFO queue (for several 
reasons I cannot process the update message right away). In pseudo-code:
--
int recv_update_message()
{
        int result;

        if ((result = probe_for_update_message()) == TRUE)
                queue(update_message);
        return(result);
}
--
The asynchronous send code in pseudo-code looks like:
--
MPI_Isend(update_message, &request);
while(TRUE)
{
        //deal with deadlock
        //I assume my deadlocks are caused by running out of system buffer space
        //hopefully polling pending update messages frees up buffer space

        recv_update_message();

        MPI_Test(&request, &flag);
        if (flag) break;
}
--
The asynchronous receive code in pseudo-code looks like:
--
//first check the FIFO queue
if (dequeue(update_message))
        return(TRUE);
else
{
        int result;
        if ((result = recv_update_message()) == INVALID)
                return(INVALID);
        if (result == TRUE)
                dequeue(update_message);
        return(result);
}
--
As a further refinement I use a queue per processor, and recv_update_message 
first tries to receive messages for the least used queues, but if deadlock is 
detected it tries to receive messages for all queues:
--
MPI_Isend(update_message, &request);
while(TRUE)
nwaitx = 16; //threshold for deadlock
nwait = 0;
{
        if (nwait > 2 * nwaitx) 
        {
                printf("possible deadlock detected\n");
                nwaitx = nwait;
                recv_update_message(all_queues);
        }
        else
        {
                recv_update_message(least_used_queues_only);
        }

        MPI_Test(&request, &flag);
        if (flag) break;
        nwait++;
}
--

Gijsbert


Reply via email to