Bind mutex to object
If you wish to achieve that the std::mutex
will only be held until an operation is performed on the protected object, you can write a wrapper class
as follows:
#include <cstdio>#include <mutex>template<typename T>class LockAssignable {public: LockAssignable& operator=(const T& t) { std::lock_guard<std::mutex> lk(m_mutex); m_protected = t; return *this; } operator T() const { std::lock_guard<std::mutex> lk(m_mutex); return m_protected; } /* other stuff */private: mutable std::mutex m_mutex; T m_protected {};};inline int factorial(int n) { return (n > 1 ? n * factorial(n - 1) : 1);}int main() { int var = 5; LockAssignable<int> mvar; mvar = factorial(var); printf("Result: %d\n", static_cast<int>(mvar)); return 0;}
In the example above the factorial
will be calculated in advance and the m_mutex
will be acquired only when the assignment or the implicit conversion operator being called on mvar
.
For the primitive data types you can use std::atomic
with std::memory_order_relaxed
.The documentation states that:
there are no synchronization or ordering constraints imposed on other reads or writes, only this operation's atomicity is guaranteed
In the following example, the atomicity of the assignation is guaranteed, but the compiler should be able to move the operations.
std::atomic<int> z = {0};int a = 3;z.store(a*a, std::memory_order_relaxed);
For objects, I thought of several solutions, but:
- There is no standard way to remove ordering requirements from
std::mutex
. - It is not possible to create a
std::atomic<std::vector>
. - It is not possible to create a spinlock using
std::memory_order_relaxed
(see the example).
I have found some answers that state that:
- If the function is not visible in the compilation unit, the compiler generates a barrier because it does not know which variables it uses.
- If the function is visible and there is a mutex, the compiler generates a barrier.For example, see this and this
So, in order to express that mvar_mutex is bound to the variable, you can use some classes as stated by the other answers but I do not think it is possible to fully allow the reordering of the code.
I want to express that mvar_mutex is bound to the variable mvar and protects only that variable.
You can't do this. A mutex actually guards the critical region of machine instructons between the acquisition and release. Only by convention is that associated with a particular instance of shared data.
To avoid doing unnecessary steps inside the critical region, keep the critical regions as simple as possible. In a critical region, only with local variables which the compiler can "see" are obviously not shared with other threads, and with one set of shared data belonging to that mutex. Try not to access other data in the critical region that might be suspected of being shared.
If you could have your proposed language feature, it would only introduce the possibility of error into a program. All it does is take code which is now correct, and make some of it incorrect (in exchange for the promise of some speed: that some code stays correct and is faster, because extraneous computations are moved out of the critical region).
It's like taking a language which already has a nice order of evaluation, in which a[i] = i++
is well defined, and screwing it up with unspecified evaluation order.