use mutex to avoid race condition when accessing thermo data during run

This commit is contained in:
Axel Kohlmeyer
2025-01-12 23:24:48 -05:00
parent a5c3305c42
commit 0aadc4cf46
6 changed files with 75 additions and 7 deletions

View File

@ -121,9 +121,9 @@ void Finish::end(int flag)
MPI_Allreduce(&cpu_loop,&tmp,1,MPI_DOUBLE,MPI_SUM,world);
cpu_loop = tmp/nprocs;
if (time_loop > 0.0) cpu_loop = cpu_loop/time_loop*100.0;
output->thermo->footer();
if (me == 0) {
output->thermo->footer();
int ntasks = nprocs * nthreads;
utils::logmesg(lmp,"Loop time of {:.6g} on {} procs for {} steps with {} atoms\n\n",
time_loop,ntasks,update->nsteps,atom->natoms);

View File

@ -853,7 +853,11 @@ This differs from :cpp:func:`lammps_get_thermo` in that it does **not**
trigger an evaluation. Instead it provides direct access to a read-only
location of the last thermo output data and the corresponding keyword
strings. How to handle the return value depends on the value of the *what*
argument string.
argument string. When accessing the data from a concurrent thread while
LAMMPS is running, the cache needs to be locked first and then unlocked
after the data is obtained, so that the data is not corrupted while
reading in case LAMMPS wants to update it at the same time. Outside
of a run, the lock/unlock calls have no effect.
.. note::
@ -902,6 +906,14 @@ argument string.
- actual field data for column
- pointer to int, int64_t or double
- yes
* - lock
- acquires lock to thermo data cache
- NULL pointer
- no
* - unlock
- releases lock to thermo data cache
- NULL pointer
- no
\endverbatim
*
@ -957,8 +969,14 @@ void *lammps_last_thermo(void *handle, const char *what, int index)
} else if (field.type == multitype::LAMMPS_DOUBLE) {
val = (void *) &field.data.d;
}
} else if (strcmp(what, "lock") == 0) {
th->lock_cache();
val = nullptr;
} else if (strcmp(what, "unlock") == 0) {
th->unlock_cache();
val = nullptr;
} else val = nullptr;
}
END_CAPTURE
return val;

View File

@ -48,6 +48,7 @@
#include <cmath>
#include <cstring>
#include <mutex>
#include <stdexcept>
using namespace LAMMPS_NS;
@ -100,8 +101,8 @@ static char fmtbuf[512];
/* ---------------------------------------------------------------------- */
Thermo::Thermo(LAMMPS *_lmp, int narg, char **arg) :
Pointers(_lmp), style(nullptr), vtype(nullptr), field2index(nullptr), argindex1(nullptr),
argindex2(nullptr), temperature(nullptr), pressure(nullptr), pe(nullptr)
Pointers(_lmp), style(nullptr), vtype(nullptr), cache_mutex(nullptr), field2index(nullptr),
argindex1(nullptr), argindex2(nullptr), temperature(nullptr), pressure(nullptr), pe(nullptr)
{
style = utils::strdup(arg[0]);
@ -208,6 +209,7 @@ void Thermo::init()
ValueTokenizer *format_line = nullptr;
if (format_line_user.size()) format_line = new ValueTokenizer(format_line_user);
lock_cache();
field_data.clear();
field_data.resize(nfield);
std::string format_this, format_line_user_def;
@ -277,6 +279,7 @@ void Thermo::init()
format[i] += fmt::format("{:<8} = {} ", keyword[i], format_this);
}
}
unlock_cache();
// chop off trailing blank or add closing bracket if needed and then add newline
if (lineflag == ONELINE)
@ -320,6 +323,9 @@ void Thermo::init()
if (index_press_scalar >= 0) pressure = computes[index_press_scalar];
if (index_press_vector >= 0) pressure = computes[index_press_vector];
if (index_pe >= 0) pe = computes[index_pe];
// create mutex to protect access to cached thermo data
cache_mutex = new std::mutex;
}
/* ----------------------------------------------------------------------
@ -366,11 +372,19 @@ void Thermo::header()
/* ---------------------------------------------------------------------- */
// called at the end of a run from Finish class
void Thermo::footer()
{
if (comm->me == 0) {
if (lineflag == YAMLLINE) utils::logmesg(lmp, "...\n");
}
// no more locking for cached thermo data access needed
delete cache_mutex;
cache_mutex = nullptr;
}
/* ---------------------------------------------------------------------- */
void Thermo::compute(int flag)
@ -422,6 +436,7 @@ void Thermo::compute(int flag)
}
// add each thermo value to line with its specific format
lock_cache();
field_data.clear();
field_data.resize(nfield);
@ -441,6 +456,7 @@ void Thermo::compute(int flag)
field_data[ifield] = bivalue;
}
}
unlock_cache();
// print line to screen and logfile
@ -579,7 +595,8 @@ void Thermo::modify_params(int narg, char **arg)
if (iarg + 2 > narg) error->all(FLERR, "Illegal thermo_modify command");
triclinic_general = utils::logical(FLERR, arg[iarg + 1], false, lmp);
if (triclinic_general && !domain->triclinic_general)
error->all(FLERR,"Thermo_modify triclinic/general cannot be used "
error->all(FLERR,
"Thermo_modify triclinic/general cannot be used "
"if simulation box is not general triclinic");
iarg += 2;
@ -1566,6 +1583,26 @@ int Thermo::evaluate_keyword(const std::string &word, double *answer)
return 0;
}
/* ---------------------------------------------------------------------- */
// lock cache for current thermo data
void Thermo::lock_cache()
{
// no locking outside of a run
if (!cache_mutex) return;
cache_mutex->lock();
}
// unlock cache for current thermo data
void Thermo::unlock_cache()
{
// no locking outside of a run
if (!cache_mutex) return;
cache_mutex->unlock();
}
/* ----------------------------------------------------------------------
extraction of Compute, Fix, Variable results
compute/fix are normalized by atoms if returning extensive value

View File

@ -17,6 +17,10 @@
#include "pointers.h"
#include <map>
namespace std {
class mutex;
}
namespace LAMMPS_NS {
class Thermo : protected Pointers {
@ -43,6 +47,8 @@ class Thermo : protected Pointers {
int evaluate_keyword(const std::string &, double *);
// for accessing cached thermo and related data
void lock_cache();
void unlock_cache();
const int *get_line() const { return &nline; }
const char *get_image_fname() const { return image_fname.c_str(); }
@ -82,6 +88,9 @@ class Thermo : protected Pointers {
int nline;
std::string image_fname;
// mutex for locking the cache
std::mutex *cache_mutex;
// data used by routines that compute single values
int ivalue; // integer value to print

View File

@ -61,6 +61,8 @@
Highlight warnings and error messages in Output window
Make Tutorial wizards more compact
Include download and compilation of WHAM software from Alan Grossfield
Add dialog to run WHAM directly from LAMMPS-GUI
Use mutex to avoid corruption of thermo data
</description>
</release>
<release version="1.6.11" timestamp="1725080055">

View File

@ -1015,6 +1015,7 @@ void LammpsGui::logupdate()
void *ptr = lammps.last_thermo("setup", 0);
if (ptr && *(int *)ptr) return;
lammps.last_thermo("lock", 0);
ptr = lammps.last_thermo("num", 0);
if (ptr) {
int ncols = *(int *)ptr;
@ -1066,6 +1067,7 @@ void LammpsGui::logupdate()
chartwindow->add_data(step, data, i);
}
}
lammps.last_thermo("unlock", 0);
}
// update list of available image file names