You can chose a root rank and combine an asynchronous send with an asynchronous broadcast that originates from this root. Here is a small example:
#include <stdio.h>
#include <mpi.h>
int main()
{
int size, rank;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
const int root = 0;
const int found_tag = 42;
const long long chunk = 100000ll;
const long long target = 134861523ll;
MPI_Request found_request;
long long found_item;
if (rank == root) {
MPI_Irecv(&found_item, 1, MPI_LONG_LONG, MPI_ANY_SOURCE, found_tag, MPI_COMM_WORLD, &found_request);
} else {
MPI_Ibcast(&found_item, 1, MPI_LONG_LONG, root, MPI_COMM_WORLD, &found_request);
}
for (long long my_number = rank;; my_number += size) {
if (my_number == target) {
found_item = my_number;
printf("I found it: %d, %lld\n", rank, found_item);
// We don't stop here, we will continue until the root tells us to stop
// This also works if we are the root
MPI_Send(&my_number, 1, MPI_LONG_LONG, root, found_tag, MPI_COMM_WORLD);
}
// Avoid checking MPI_Test too often.
if ((1 + (my_number / size)) % chunk == 0) {
if (rank == root) {
int found = 0;
MPI_Test(&found_request, &found, MPI_STATUS_IGNORE);
if (found) {
printf("Someone told me that he found it: %d, %lld\n", rank, found_item);
MPI_Request bcast_request;
MPI_Ibcast(&found_item, 1, MPI_LONG_LONG, root, MPI_COMM_WORLD, &bcast_request);
MPI_Wait(&bcast_request, MPI_STATUS_IGNORE);
break;
}
} else {
int found = 0;
MPI_Test(&found_request, &found, MPI_STATUS_IGNORE);
if (found) {
break;
}
}
}
}
printf("%d, %lld\n", rank, found_item);
MPI_Finalize();
}
This code assumes that you only find exactly one number - once. Finding multiple numbers will require some additional code.
As you noted, you cannot post a broadcast with an unknown sender. Now you could post an MPI_Allreduce
(or even MPI_Allgather
) - after which all ranks will know the found value. However, you cannot just post an asynchronous one once - because you cannot change the value after you posted it.