Краткое объяснение
Блокировка / разблокировка MPI сами по себе не вызывают атомных обновлений.
Вы не должны использовать блокировку / разблокировку больше, чем необходимо в любом случае. Вместо этого используйте флэш. Блокируйте и разблокируйте окно только тогда, когда вы выделите и освободите его.
Вы можете получить атомарность, используя функции накопления MPI (Accumulate, Get_accumulate, Fetch_and_op, Compare_and_swap) или - и только в случае разделяемой памяти - вы можете использовать атомарные примитивы, связанные с вашим компилятором. Поскольку это немного сложно с C11 / C ++ 11, потому что они требуют типов, я покажу пример ниже со встроенными функциями, которые допускаются большинством, если не всеми распространенными компиляторами.
Предложение по изменению кода
Я не знаю, правильно ли это. Это просто демонстрирует концепции, отмеченные выше.
MPI_Comm nodecomm;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_split_type(MPI_COMM_WORLD, MPI_COMM_TYPE_SHARED, rank,
MPI_INFO_NULL, &nodecomm);
MPI_Comm_size(nodecomm, &nodesize);
MPI_Comm_rank(nodecomm, &noderank);
int local_xx_size = 0;
if (noderank == 0){
local_xx_size = xx_size;
}
MPI_Win win_xx;
MPI_Aint winsize;
double *xx, *local_xx;
MPI_Win_allocate_shared(local_xx_size*sizeof(double), sizeof(double), MPI_INFO_NULL, nodecomm, &local_xx, &win_xx);
MPI_Win_lock_all(0, win_xx);
xx = local_xx;
if (noderank != 0){
MPI_Win_shared_query(win_xx, 0, &winsize, &windisp, &xx);
}
//init xx
if(noderank == 0){
for (i=0; i<xx_size; i++){
xx[i]=0.0;
}
}
MPI_Barrier(nodecomm);
long counter = 0;
for(i = 0; i < largeNum; i++) {
//some calculations
for(j = 0; j < xx_size; j++) {
//calculate res
// xx[counter] += res; //update value
#ifdef USE_RMA_ATOMICS
// check the arguments - I don't know if I calculate the target+displacement right
int target = counter/local_xx_size;
MPI_Aint disp = counter%local_xx_size;
MPI_Accumulate(&res, MPI_LONG, target, disp, 1, MPI_LONG, MPI_SUM, win_xx);
MPI_Win_flush(target, win_xx);
#else
# ifdef USE_NEWER_INTRINSICS // GCC, Clang, Intel support this AFAIK
__atomic_fetch_add (&xx[counter], res, __ATOMIC_RELAXED);
# else // GCC, Clang, Intel, IBM support this AFAIK
__sync_fetch_and_add(&xx[counter], res);
# endof
#endif
}
}
MPI_Barrier(nodecomm);
MPI_Win_unlock_all(win_xx);
MPI_Win_free(&win_xx);