From 018bdce8a96722fce641788226dd4bce6c03203c Mon Sep 17 00:00:00 2001 From: Martin Quinson Date: Sun, 7 Aug 2016 18:35:56 +0200 Subject: [PATCH] further improve the doc of s4u::Mutex --- doc/doxygen/module-s4u.doc | 24 +++++++++++- doc/doxygen/uhood_switch.doc | 73 ----------------------------------- include/simgrid/s4u/Mutex.hpp | 3 ++ src/s4u/s4u_mutex.cpp | 10 +++++ 4 files changed, 36 insertions(+), 74 deletions(-) diff --git a/doc/doxygen/module-s4u.doc b/doc/doxygen/module-s4u.doc index 324edb0fcc..213049a257 100644 --- a/doc/doxygen/module-s4u.doc +++ b/doc/doxygen/module-s4u.doc @@ -10,9 +10,31 @@ SimGrid will be possible in S4U. that path unless you know what you are doing. If unsure, proceed to @ref MSG_API instead. - Unsurprisingly, the S4U interface matches the concepts presented in @ref starting_components "the introduction". You should read this page first, to not get lost in the amount of classes provided here. +@section s4u_raii Memory Management of S4U objects + +For sake of simplicity, we use +[RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) +everywhere in S4U. This is an idiom where resources are automatically +managed through the context. Provided that you never manipulate +objects of type Foo directly but always FooPtr references, you will +never have to explicitely release the resource that you use nor to +free the memory of unused objects. + +Here is a little example: + +@code{cpp} +void myFunc() +{ + simgrid::s4u::MutexPtr mutex = simgrid::s4u::Mutex::createMutex(); // Too bad we cannot use `new` here + + mutex->lock(); // use the mutex as a simple reference + // bla bla + mutex->unlock(); + +} // The mutex will get automatically freed because the only existing reference gets out of scope +@endcode */ diff --git a/doc/doxygen/uhood_switch.doc b/doc/doxygen/uhood_switch.doc index bc6b8f3a2f..43fac9b403 100644 --- a/doc/doxygen/uhood_switch.doc +++ b/doc/doxygen/uhood_switch.doc @@ -621,79 +621,6 @@ instead of one to do the same job (one in `kernelAsync()` and one in ## Mutexes and condition variables -## Mutexes - -SimGrid has had a C-based API for mutexes and condition variables for -some time. These mutexes are different from the standard -system-level mutex (`std::mutex`, `pthread_mutex_t`, etc.) because -they work at simulation-level. Locking on a simulation mutex does -not block the thread directly but makes a simcall -(`simcall_mutex_lock()`) which asks the simulation kernel to wake the calling -actor when it can get ownership of the mutex. Blocking directly at the -OS level would deadlock the simulation. - -Reusing the C++ standard API for our simulation mutexes has many -benefits: - - * it makes it easier for people familiar with the `std::mutex` to - understand and use SimGrid mutexes; - - * we can benefit from a proven API; - - * we can reuse from generic library code in SimGrid. - -We defined a reference-counted `Mutex` class for this (which supports -the [`Lockable`](http://en.cppreference.com/w/cpp/concept/Lockable) -requirements, see -[`[thread.req.lockable.req]`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf#page=1175) -in the C++14 standard): - -@code{cpp} -class Mutex { - friend ConditionVariable; -private: - friend simgrid::simix::Mutex; - simgrid::simix::Mutex* mutex_; - Mutex(simgrid::simix::Mutex* mutex) : mutex_(mutex) {} -public: - - friend void intrusive_ptr_add_ref(Mutex* mutex); - friend void intrusive_ptr_release(Mutex* mutex); - using Ptr = boost::intrusive_ptr; - - // No copy: - Mutex(Mutex const&) = delete; - Mutex& operator=(Mutex const&) = delete; - - static Ptr createMutex(); - -public: - void lock(); - void unlock(); - bool try_lock(); -}; -@endcode - -The methods are simply wrappers around existing simcalls: - -@code{cpp} -void Mutex::lock() -{ - simcall_mutex_lock(mutex_); -} -@endcode - -Using the same API as `std::mutex` (`Lockable`) means we can use existing -C++-standard code such as `std::unique_lock` or -`std::lock_guard` for exception-safe mutex handling[^lock]: - -@code{cpp} -{ - std::lock_guard lock(*mutex); - sum += 1; -} -@endcode - ### Condition Variables Similarly SimGrid already had simulation-level condition variables diff --git a/include/simgrid/s4u/Mutex.hpp b/include/simgrid/s4u/Mutex.hpp index 0b3ebc8c59..93db75ea3f 100644 --- a/include/simgrid/s4u/Mutex.hpp +++ b/include/simgrid/s4u/Mutex.hpp @@ -28,6 +28,9 @@ class ConditionVariable; * Instead, you should use the present class, that is a drop-in replacement of * [std::mutex](http://en.cppreference.com/w/cpp/thread/mutex). * + * As for any S4U object, Mutexes are using the @ref "RAII idiom" s4u_raii for memory management. + * Use createMutex() to get a ::MutexPtr to a newly created mutex and only manipulate ::MutexPtr. + * */ XBT_PUBLIC_CLASS Mutex { friend ConditionVariable; diff --git a/src/s4u/s4u_mutex.cpp b/src/s4u/s4u_mutex.cpp index ba83148c58..4f2cce6deb 100644 --- a/src/s4u/s4u_mutex.cpp +++ b/src/s4u/s4u_mutex.cpp @@ -13,21 +13,31 @@ namespace simgrid { namespace s4u { +/** @brief Blocks the calling actor until the mutex can be obtained */ void Mutex::lock() { simcall_mutex_lock(mutex_); } +/** @brief Release the ownership of the mutex, unleashing a blocked actor (if any) + * + * Will fail if the calling actor does not own the mutex. + */ void Mutex::unlock() { simcall_mutex_unlock(mutex_); } +/** @brief Acquire the mutex if it's free, and return false (without blocking) if not */ bool Mutex::try_lock() { return simcall_mutex_trylock(mutex_); } +/** @brief Create a new mutex + * + * See @ref s4u_raii. + */ MutexPtr Mutex::createMutex() { smx_mutex_t mutex = simcall_mutex_init(); -- 2.20.1