- Mailbox: Mailbox.by_name()
- Added the following bindings:
- this_actor.warning()
- - Mailbox.put_init() [example: examples/python/comm-waitallfor]
- - Comm.detach() [example: examples/python/comm-waitallfor]
+ - Mailbox.put_init() [example: examples/python/comm-waitallfor/]
+ - Comm.detach() [example: examples/python/comm-waitallfor/]
- Comm.wait_for() [example: examples/python/comm-waitfor/]
- Comm.wait_any_for()
- - Comm.wait_all_for() [example: examples/python/comm-waitallfor]
+ - Comm.wait_all_for() [example: examples/python/comm-waitallfor/]
+ - Mutex [example: examples/python/synchro-mutex/]
Build System:
- Remove target "make uninstall" which was incomplete and no longer maintained.
Mutex
==============
-.. doxygenclass:: simgrid::s4u::Mutex
+.. tabs::
+
+ .. group-tab:: C++
+
+ .. doxygenclass:: simgrid::s4u::Mutex
+
+ .. group-tab:: Python
+
+ .. autoclass:: simgrid.Mutex
Basic management
----------------
.. doxygenfunction:: simgrid::s4u::Mutex::create()
+ .. group-tab:: Python
+
+ .. code-block:: Python
+
+ from simgrid import Mutex
+ mutex = Mutex()
+
.. group-tab:: C
.. code-block:: C
.. doxygenfunction:: simgrid::s4u::Mutex::try_lock()
.. doxygenfunction:: simgrid::s4u::Mutex::unlock()
+ .. group-tab:: Python
+
+ .. automethod:: simgrid.Mutex.lock()
+ .. automethod:: simgrid.Mutex.try_lock()
+ .. automethod:: simgrid.Mutex.unlock()
+
.. group-tab:: C
.. doxygenfunction:: sg_mutex_lock(sg_mutex_t mutex)
.. example-tab:: examples/cpp/synchro-mutex/s4u-synchro-mutex.cpp
+ .. example-tab:: examples/python/synchro-mutex/synchro-mutex.py
+
Semaphore
^^^^^^^^^
comm-wait comm-waitall comm-waitallfor comm-waitany comm-waitfor
exec-async exec-basic exec-dvfs exec-remote
platform-profile platform-failures
- network-nonlinear clusters-multicpu io-degradation exec-cpu-nonlinear)
+ network-nonlinear clusters-multicpu io-degradation exec-cpu-nonlinear
+ synchro-mutex)
set(tesh_files ${tesh_files} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.tesh)
set(examples_src ${examples_src} ${CMAKE_CURRENT_SOURCE_DIR}/${example}/${example}.py)
--- /dev/null
+from argparse import ArgumentParser
+from dataclasses import dataclass
+import sys
+
+from simgrid import Actor, Engine, Host, Mutex, this_actor
+
+
+def create_parser() -> ArgumentParser:
+ parser = ArgumentParser()
+ parser.add_argument(
+ '--platform',
+ type=str,
+ required=True,
+ help='path to the platform description'
+ )
+ parser.add_argument(
+ '--workers',
+ type=int,
+ default=6,
+ help='number of workers to start'
+ )
+ parser.add_argument(
+ '--trials-before-success',
+ type=int,
+ default=0,
+ help='number of attempts each workers need to make before getting the correct answer'
+ ' (i.e. number of simulated failures)'
+ )
+ return parser
+
+
+@dataclass
+class ResultHolder:
+ value: int
+
+
+class CalculationError(RuntimeError):
+ """ Fake calculation error
+ """
+ pass
+
+
+def worker_context_manager(mutex: Mutex, trials_before_success: int, result: ResultHolder):
+ """ Worker that uses a context manager to acquire/release the shared mutex
+ :param mutex: Shared mutex that guards read/write access to the shared result
+ :param trials_before_success: Number of simulated calculation failures before success
+ :param result: Shared result which will be updated by the worker
+ """
+ this_actor.info(f"I just started")
+ for trial in range(trials_before_success + 1):
+ try:
+ with mutex:
+ this_actor.info(f"acquired the mutex with context manager")
+ this_actor.sleep_for(1)
+ if trial < trials_before_success:
+ raise CalculationError("did not manage to find the correct answer")
+ result.value += 1
+ this_actor.info(f"updated shared result, which is now {result.value}")
+ except CalculationError as e:
+ this_actor.warning(f"ran in trouble while calculating: {e}. Will retry shortly.")
+ finally:
+ this_actor.info(f"released the mutex after leaving the context manager")
+ this_actor.info("Bye now!")
+
+
+def worker(mutex: Mutex, trials_before_success: int, result: ResultHolder):
+ """ Worker that manually acquires/releases the shared mutex
+ :param mutex: Shared mutex that guards read/write access to the shared result
+ :param trials_before_success: Number of simulated calculation failures before success
+ :param result: Shared result which will be updated by the worker
+ """
+ this_actor.info(f"I just started")
+ for trial in range(trials_before_success + 1):
+ try:
+ mutex.lock()
+ this_actor.info(f"acquired the mutex manually")
+ this_actor.sleep_for(1)
+ if trial < trials_before_success:
+ raise CalculationError("did not manage to find the correct answer")
+ result.value += 1
+ this_actor.info(f"updated shared result, which is now {result.value}")
+ except CalculationError as e:
+ this_actor.warning(f"ran in trouble while calculating: {e}. Will retry shortly.")
+ finally:
+ this_actor.info(f"released the mutex manually")
+ mutex.unlock()
+ this_actor.info("Bye now!")
+
+
+def master(settings):
+ """ Spawns `--workers` workers and wait until they have all updated the shared result, then displays it before
+ leaving. Alternatively spawns `worker_context_manager()` and `worker()` workers.
+ :param settings: Simulation settings
+ """
+ result = ResultHolder(value=0)
+ mutex = Mutex()
+ actors = []
+ for i in range(settings.workers):
+ use_worker_context_manager = i % 2 == 0
+ actors.append(
+ Actor.create(
+ f"worker-{i}(mgr)" if use_worker_context_manager else f"worker-{i}",
+ Host.by_name("Jupiter" if use_worker_context_manager else "Tremblay"),
+ worker_context_manager if use_worker_context_manager else worker,
+ mutex,
+ settings.trials_before_success,
+ result
+ )
+ )
+ [actor.join() for actor in actors]
+ this_actor.info(f"The final result is: {result.value}")
+
+
+def main():
+ settings = create_parser().parse_known_args()[0]
+ e = Engine(sys.argv)
+ e.load_platform(settings.platform)
+ Actor.create("master", Host.by_name("Tremblay"), master, settings)
+ e.run()
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+#!/usr/bin/env tesh
+
+p Testing Mutex
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --workers 0 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+>[ 0.000000] (1:master@Tremblay) The final result is: 0
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --workers 1 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) I just started
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) updated shared result, which is now 1
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) Bye now!
+>[ 1.000000] (1:master@Tremblay) The final result is: 1
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --workers 1 --trials-before-success 5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) I just started
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 2.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 2.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 2.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 3.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 3.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 3.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 4.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 4.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 4.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 5.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 5.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 5.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 6.000000] (2:worker-0(mgr)@Jupiter) updated shared result, which is now 1
+>[ 6.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 6.000000] (2:worker-0(mgr)@Jupiter) Bye now!
+>[ 6.000000] (1:master@Tremblay) The final result is: 1
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --workers 5 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) I just started
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 0.000000] (3:worker-1@Tremblay) I just started
+>[ 0.000000] (4:worker-2(mgr)@Jupiter) I just started
+>[ 0.000000] (5:worker-3@Tremblay) I just started
+>[ 0.000000] (6:worker-4(mgr)@Jupiter) I just started
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) updated shared result, which is now 1
+>[ 1.000000] (3:worker-1@Tremblay) acquired the mutex manually
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) Bye now!
+>[ 2.000000] (3:worker-1@Tremblay) updated shared result, which is now 2
+>[ 2.000000] (3:worker-1@Tremblay) released the mutex manually
+>[ 2.000000] (4:worker-2(mgr)@Jupiter) acquired the mutex with context manager
+>[ 2.000000] (3:worker-1@Tremblay) Bye now!
+>[ 3.000000] (4:worker-2(mgr)@Jupiter) updated shared result, which is now 3
+>[ 3.000000] (5:worker-3@Tremblay) acquired the mutex manually
+>[ 3.000000] (4:worker-2(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 3.000000] (4:worker-2(mgr)@Jupiter) Bye now!
+>[ 4.000000] (5:worker-3@Tremblay) updated shared result, which is now 4
+>[ 4.000000] (5:worker-3@Tremblay) released the mutex manually
+>[ 4.000000] (6:worker-4(mgr)@Jupiter) acquired the mutex with context manager
+>[ 4.000000] (5:worker-3@Tremblay) Bye now!
+>[ 5.000000] (6:worker-4(mgr)@Jupiter) updated shared result, which is now 5
+>[ 5.000000] (6:worker-4(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 5.000000] (6:worker-4(mgr)@Jupiter) Bye now!
+>[ 5.000000] (1:master@Tremblay) The final result is: 5
+
+$ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${bindir:=.}/synchro-mutex.py --platform ${platfdir}/two_hosts.xml --workers 3 --trials-before-success 2 "--log=root.fmt:[%10.6r]%e(%i:%a@%h)%e%m%n"
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) I just started
+>[ 0.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 0.000000] (3:worker-1@Tremblay) I just started
+>[ 0.000000] (4:worker-2(mgr)@Jupiter) I just started
+>[ 1.000000] (3:worker-1@Tremblay) acquired the mutex manually
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 1.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 2.000000] (3:worker-1@Tremblay) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 2.000000] (3:worker-1@Tremblay) released the mutex manually
+>[ 2.000000] (4:worker-2(mgr)@Jupiter) acquired the mutex with context manager
+>[ 3.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 3.000000] (4:worker-2(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 3.000000] (4:worker-2(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 4.000000] (3:worker-1@Tremblay) acquired the mutex manually
+>[ 4.000000] (2:worker-0(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 4.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 5.000000] (3:worker-1@Tremblay) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 5.000000] (3:worker-1@Tremblay) released the mutex manually
+>[ 5.000000] (4:worker-2(mgr)@Jupiter) acquired the mutex with context manager
+>[ 6.000000] (2:worker-0(mgr)@Jupiter) acquired the mutex with context manager
+>[ 6.000000] (4:worker-2(mgr)@Jupiter) ran in trouble while calculating: did not manage to find the correct answer. Will retry shortly.
+>[ 6.000000] (4:worker-2(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 7.000000] (2:worker-0(mgr)@Jupiter) updated shared result, which is now 1
+>[ 7.000000] (3:worker-1@Tremblay) acquired the mutex manually
+>[ 7.000000] (2:worker-0(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 7.000000] (2:worker-0(mgr)@Jupiter) Bye now!
+>[ 8.000000] (3:worker-1@Tremblay) updated shared result, which is now 2
+>[ 8.000000] (3:worker-1@Tremblay) released the mutex manually
+>[ 8.000000] (4:worker-2(mgr)@Jupiter) acquired the mutex with context manager
+>[ 8.000000] (3:worker-1@Tremblay) Bye now!
+>[ 9.000000] (4:worker-2(mgr)@Jupiter) updated shared result, which is now 3
+>[ 9.000000] (4:worker-2(mgr)@Jupiter) released the mutex after leaving the context manager
+>[ 9.000000] (4:worker-2(mgr)@Jupiter) Bye now!
+>[ 9.000000] (1:master@Tremblay) The final result is: 3
#include <simgrid/s4u/Host.hpp>
#include <simgrid/s4u/Link.hpp>
#include <simgrid/s4u/Mailbox.hpp>
+#include <simgrid/s4u/Mutex.hpp>
#include <simgrid/s4u/NetZone.hpp>
#include <simgrid/version.h>
using simgrid::s4u::Host;
using simgrid::s4u::Link;
using simgrid::s4u::Mailbox;
+using simgrid::s4u::Mutex;
+using simgrid::s4u::MutexPtr;
XBT_LOG_NEW_DEFAULT_CATEGORY(python, "python");
.def("wait", &simgrid::s4u::Exec::wait, py::call_guard<py::gil_scoped_release>(),
"Block until the completion of that execution.");
+ /* Class Mutex */
+ py::class_<Mutex, MutexPtr>(m, "Mutex",
+ "A classical mutex, but blocking in the simulation world."
+ "See the C++ documentation for details.")
+ .def(py::init<>(&Mutex::create))
+ .def("lock", &Mutex::lock, py::call_guard<py::gil_scoped_release>(), "Block until the mutex is acquired.")
+ .def("try_lock", &Mutex::try_lock, py::call_guard<py::gil_scoped_release>(),
+ "Try to acquire the mutex. Return true if the mutex was acquired, false otherwise.")
+ .def("unlock", &Mutex::unlock, py::call_guard<py::gil_scoped_release>(), "Release the mutex")
+ // Allow mutexes to be automatically acquired/released with a context manager: `with mutex: ...`
+ .def("__enter__", [](Mutex* self){ self->lock(); }, py::call_guard<py::gil_scoped_release>())
+ .def("__exit__", [](Mutex* self, py::object&, py::object&, py::object&){ self->unlock(); },
+ py::call_guard<py::gil_scoped_release>());
+
/* Class Actor */
py::class_<simgrid::s4u::Actor, ActorPtr>(m, "Actor",
"An actor is an independent stream of execution in your distributed "
"Returns True if that actor is a daemon and will be terminated automatically when the last non-daemon actor "
"terminates.")
.def("join", py::overload_cast<double>(&Actor::join, py::const_), py::call_guard<py::gil_scoped_release>(),
- "Wait for the actor to finish (more info in the C++ documentation).", py::arg("timeout"))
+ "Wait for the actor to finish (more info in the C++ documentation).", py::arg("timeout") = -1)
.def("kill", &Actor::kill, py::call_guard<py::gil_scoped_release>(), "Kill that actor")
.def("self", &Actor::self, "Retrieves the current actor.")
.def("is_suspended", &Actor::is_suspended, "Returns True if that actor is currently suspended.")