in my program I have global data.
Every program module must have read and write access to the data. As of now, I do not use threading, but Qt's signals and slots and therefore - although I did not yet encounter crashes - I think I'll need synchronization somewhen.
Therefore, every module holds the data like this:
const std::vector<T>& data;
where T is a custom class. Therefore, every module can read the data. To keep it consistent, the vector itself is const to prohibit concurrent deletions or removals. Those are done using global functions (like addToData(T elem), removeFromData(int id)) which can be synchronized. Note that the vector itself is declared to be shared by reference, such that changes in one of the global functions above will result in consistent data in every program module.
==> That means that data can be read and added/removed from everywhere in a safe way.
The problem I encountered is modification of the data. The setters of T are aware of the race-conditions. Using data, I want to allow calls like data.at(3).setAttr("hello"), but for constant vectors, at() just returns constant references. Why and how can I make it work? I can cast the constness away, but that feels wrong.
I am also open for suggestions considering my architecture.
This scenario is exactly where you want to cast constness away. You have carefully designed your system to work correctly so don't feel badly about casting away const when you're completely ready for it's and it the right thing to do.
Synchronizing writes leaving reads non-synchronized may/will corrupt memory too.
Casting constancy away smells.
Working low overhead solution (though not well encapsulated) is below. Idea is well summarized in a #JonathanWakely's comment: "add a global function that takes a functor and applies it to the non-const vector"
header.h
struct no_synchronization {
struct mutex {}
struct guard {
guard(mutex&) {}
};
};
struct serialized {
typedef std::mutex mutex;
typedef std::lock_guard<mutex> guard;
};
template <class T, class S = no_synchronization>
class spaghetti {
typedef typename S::mutex mutex;
typedef typename S::guard guard;
static mutex mutex_;
static std::vector<T> vector_;
template <class F>
static void read_global_vec(F const& f) {
guard lock(mutex_);
std::vector<T> const& ref = vector_;
f(ref);
}
template <class F>
static void write_global_vec(F const& f) {
guard lock(mutex_);
f(vector_);
}
}
If the contents of the vector is changing infrequently then you can use copy-on-write with a shared_ptr to keep contention to the minimum.
Since you asked for suggestions
You can wrap vector, with a class that works mostly the same. This would also get rid of the global functions you mention, which is good. If you want the instance of your class to be const, use a mutable vector internally.
const_cast, but try to hide it somewhere in a function.
Store smart pointers. I hope I'm not wrong with this (it's been a while), but I think you can retrieve a non-const element through a const smart pointer.
To elaborate on (1) since I was asked to in the comment:
You need the functionality of vector, it's a pretty good match for your needs. But the interface of vector is clumsy for what you need. This is a situation which is often encountered, and a wrapper is the default solution. A wrapper is a new class, with an interface that matches your needs, but it's implementation is pretty much just delegating all the work to another class. The goal of using a wrapper is to make the wrapper object easier to use right and harder to use wrong. It might look somewhat like this (not tested, will not compile):
class AWrapperForDemonstration
{
public:
MyCustomClass& GetByIndex(int i) const // can throw
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage[i];
}
size_t Size(int i) const
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage.size();
}
void Add(MyCustomClass& addThis)
{
std::lock_guard<std::mutex> lock(_mutex);
_storage.push_back(addThis);
}
bool Remove(MyCustomClass& removeThis)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it =_storage.find(removeThis);
if (it == _storage.end())
return false;
_storage.erase(it);
}
template <F> void ForEach(F const& f) const
{
std::lock_guard<std::mutex> lock(_mutex);
for (auto& i : _storage)
f(i);
}
private:
std::vector<MyCustomClass> _storage;
std::mutex _mutex;
}
Related
Suppose I have a class:
class A
{
private:
std::vector<MyObject> history;
std::mutex historyLock;
}
There are multiple threads initialized by that class which acquire the mutex and write to the history vector. Suppose then I have another class where I want to read that list:
class B
{
public:
B(A instanceA)
{
// I want to read the list here in a thread safe way
}
}
My intuition tells me to expose a method in class A called GetHistory(), which would lock the mutex, copy the list and return the copy.
Is there a way to read the list in class B without incurring the cost of a copy operation?
There are several ways to approach this sort of problem. One way is to use a more sophisticated structure to store your history, like an immutable vector. (An immutable vector trades iteration performance for cheap copies.) But using just standard C++, I think the easiest way is to add a traversal member function template to class A that accepts a callback:
template <class F> void TraverseHistory(F&& callback)
{
std::lock_guard guard{ historyMutex };
for (auto const& item : history)
{
callback(item);
}
}
You can also use std::function if you prefer to avoid a function template:
void TraverseHistory(std::function<void(MyObject const&)> const& callback);
Yet another option is to pass a reference to the entire vector to your callback. With that approach, the function template would look something like this:
template <class F> void ReadHistory(F&& callback)
{
std::lock_guard guard{ historyMutex };
callback(std::as_const(history));
}
I have a class that I need to make thread-safe. I'm trying to do this by putting a unique lock at the top of every function in the class. The problem is that as soon as one function calls another function (in this class) the mutexes seem to lock each other, despite being in different functions. How can I stop this from happening?
An example is a class with get() and set() functions that both use a unique_lock at the start of each function. But in set() you want to call get() at some point, but without set()'s mutex locking get()'s mutex. However the mutex in get() should still work if called directly.
Making a class "thead safe" by adding a mutex to all operations is code smell. Doing so with recursive mutex is worse, because it implies a lack of control and understanding about what was locked and what operations lock.
While it often permits some limited multithreaded access, but leads very often to deadlocks, contention and performance hell down the lane.
Lock based concurrency does not safely compose except in limited cases. You can take two correct lock-based datastructures/algorithms, connect them, and end up with incorrect/unsafe code.
Consider leaving your type single threaded, implementing const methods that can be mutually called without synchronization, then using mixtures of immutable instances and externally synchronized ones.
template<class T>
struct mutex_guarded {
template<class F>
auto read( F&& f ) const {
return access( std::forward<F>(f), *this );
}
template<class F>
auto write( F&& f ) {
return access( std::forward<F>(f), *this );
}
mutex_guarded()=default;
template<class T0, class...Ts,
std::enable_if_t<!std::is_same<mutex_guarded, std::decay_t<T0>>, bool> =true
>
mutex_guarded(T0&&t0, Ts&&ts):
t(std::forward<T0>(t0),std::forward<Ts>(ts)...)
{}
private:
template<class F, class Self>
friend auto access(F&& f, Self& self ){
auto l = self.lock();
return std::forward<F>(f)( self.t );
}
mutable std::mutex m;
T t;
auto lock() const { return std::unique_lock<std::mutex>(m); }
};
and similar for shared mutex (it has two lock overloads). access can be made public and vararg woth a bit of work (to handle things like assignment).
Now calling your own methods is no problem. External use looks like:
std::mutex_guarded<std::ostream&> safe_cout(std::cout);
safe_cout.write([&](auto& cout){ cout<<"hello "<<"world\n"; });
you can also write async wrappers (that do tasks in a thread pool and return futures) and the like.
The std::recursive_mutex is what you want. It can be locked more than one time in one thread.
It could be more clear if you provided the code.
The problem arises from the fact that all the locks share the same mutex object. a recursive lock could to some extent solve the problem.
but bear in mind that getters do not necessarily have to be locked.
I confronted the same problem years ago, There were a couple of threads working together on a proxy object. The final solution was that I had to define more than one mutex. If it is possible, make use of Qt signals or boost signal each of which helps you come up with a better solution for passing data back and forth.
While using std::recursive_mutex will work, it might incur some overhead that can be avoided.
Instead, implement all logic in private methods that do not take the lock but assume the lock is held by the current thread of execution. Then provide the necessary public methods that take the lock and forward the call to the respective private methods. In the implementation of the private methods, you are free to call other private methods without worrying about locking the mutex multiple times.
struct Widget
{
void foo()
{
std::unique_lock<std::mutex> lock{ m };
foo_impl();
}
void bar()
{
std::unique_lock<std::mutex> lock{ m };
bar_impl();
}
private:
std::mutex m;
void foo_impl()
{
bar_impl(); // Call other private methods
}
void bar_impl()
{
/* ... */
}
};
Note that this is just an alternative approach to (potentially) tackle your problem.
O wise interwebs
We have an impasse between two colleagues that we could use your help resolving in the proper C++ way. Basically we have a set of utility classes, two of which are a Mutex and SpinLock class which both have the following abridged interface:
class Mutex {
public:
Mutex();
~Mutex();
void Lock();
void Unlock();
// ...
};
Obviously this is similar to, but differently-cased than the BasicLockable concept used by std::lock_guard, so we want something similar (assume that the Mutex class is immutable in this example; we cannot add the BasicLockable concept to it). Also not all of our compilers for supported platforms are fully c++11 featured, so we cannot just use vanilla c++11 support.
One school of thought is the following implementation of a generic guard class which can be inherited to provide a generic guard class and inherit from it to create a lock-guard class:
template<class T, void (T::*EnterFn)(), void (T::*ExitFn)()>
class Guard
{
public: // copy constructor deleting omitted for brevity
Guard( T *lock ) : m_lock(lock) { (m_lock->*EnterFn)(); }
~Guard(); { (m_lock->*ExitFn)(); }
private:
T *m_lock;
};
template<class T>
class LockGuard : public Guard<T, &T::Lock, &T::Unlock>
{
public:
LockGuard(const T* lock) : Guard<T, &T::Lock, &T::Unlock>(lock) {}
};
The other school of thought is to just implement a simple lockguard:
template<class T>
class LockGuard {
T* m_lockable;
public:
LockGuard(const T* lockable) : m_lockable(lockable) { lockable->Lock(); }
~LockGuard() { m_lockable->Unlock(); }
};
Which implementation would you choose and why? What is the most proper C++(03, 11, 14, 17) way of implementing it? Is there any inherent value to having a generic Guard class as described above?
I would not want to use method pointers.
Personally, I'd want to move towards the C++11 standard tools as much as possible. So I'd write an adapter.
template<class T>
struct lock_adapter {
T* t = nullptr;
void lock() { t->Lock(); }
void unlock() { t->Unlock(); }
lock_adapter( T& tin ):t(std::addressof(tin)) {}
// default some stuff if you like
};
template<class T>
struct adapted_unique_lock:
private lock_adapter<T>,
std::unique_lock< lock_adapter<T> >
{
template<class...Args>
adapted_unique_lock(T& t, Args&&...):
lock_adapter<T>(t),
std::unique_lock< lock_adapter<T> >( *this, std::forward<Args>(args)... )
{}
adapted_unique_lock(adapted_unique_lock&&)=delete; // sadly
friend void swap( adapted_unique_lock&, adapted_unique_lock& ) = delete; // ditto
};
now adapted_unique_lock has a restricted set of functionality from a std::unique_lock.
It cannot be moved, as the unique_lock holds a pointer to this inside its implementation and does not reseat it.
Note that the richness of the entire unique_lock constructor set is available.
Functions that return adapted unique locks must store their return values in something like auto&& references until end of scope, and you cannot return them through chains until C++17.
But any code using adapted_unique_lock can be swapped to use unique_lock once T has been changed to support .lock() and .unlock(). This moves your code base towards being more standard C++11, rather than bespoke.
I'll answer the question in your title since nobody else answered it.
According to the docs, lock_guard works on any type that "meets the BasicLockable requirements". BasicLockable only requires two methods, lock() and unlock().
In order to make lock_guard work with a custom library, you need to either add lock() and unlock() methods to the library's mutex class, or wrap it in another class that has lock() and unlock() methods.
You should use those: std::mutex, std::shared_lock, std::unique_lock,
std::timed_mutex, std::shared_mutex, std::recursive_mutex, std::shared_timed_mutex, std::recursive_timed_mutex, std::lock_guard if you actually have C++11 compiler. Otherwise it is more complex, and tag c++11 on question should be removed.
You can't implement spinlock or mutex with C\C++ means, you would need add assembler or intrinsic code - making it non-portable, unless you implement it for each platform - and with many x86-64 C++11 and later compilers you can't do inline assembler.
The main problem you would run into, if you use inherent locking logic is that objects behind mutexes or spinlocks are uncopyable. As soon as you copy it or if you copy defended variable, it stops being locked. Objects that are implementing mutex mechanics are uncopyable too.
I know, it has been made quite clear in a couple of questions/answers before, that volatile is related to the visible state of the c++ memory model and not to multithreading.
On the other hand, this article by Alexandrescu uses the volatile keyword not as a runtime feature but rather as a compile time check to force the compiler into failing to accept code that could be not thread safe. In the article the keyword is used more like a required_thread_safety tag than the actual intended use of volatile.
Is this (ab)use of volatile appropriate? What possible gotchas may be hidden in the approach?
The first thing that comes to mind is added confusion: volatile is not related to thread safety, but by lack of a better tool I could accept it.
Basic simplification of the article:
If you declare a variable volatile, only volatile member methods can be called on it, so the compiler will block calling code to other methods. Declaring an std::vector instance as volatile will block all uses of the class. Adding a wrapper in the shape of a locking pointer that performs a const_cast to release the volatile requirement, any access through the locking pointer will be allowed.
Stealing from the article:
template <typename T>
class LockingPtr {
public:
// Constructors/destructors
LockingPtr(volatile T& obj, Mutex& mtx)
: pObj_(const_cast<T*>(&obj)), pMtx_(&mtx)
{ mtx.Lock(); }
~LockingPtr() { pMtx_->Unlock(); }
// Pointer behavior
T& operator*() { return *pObj_; }
T* operator->() { return pObj_; }
private:
T* pObj_;
Mutex* pMtx_;
LockingPtr(const LockingPtr&);
LockingPtr& operator=(const LockingPtr&);
};
class SyncBuf {
public:
void Thread1() {
LockingPtr<BufT> lpBuf(buffer_, mtx_);
BufT::iterator i = lpBuf->begin();
for (; i != lpBuf->end(); ++i) {
// ... use *i ...
}
}
void Thread2();
private:
typedef vector<char> BufT;
volatile BufT buffer_;
Mutex mtx_; // controls access to buffer_
};
NOTE
After the first couple of answers have appeared I think I must clarify, as I might not have used the most appropriate words.
The use of volatile is not because of what it provides at runtime but because of what it means at compile time. That is, the same trick could be pulled with the const keyword if it was as rarely used in user defined types is as volatile is. That is, there is a keyword (that happens to be spelled volatile) that allows me to block member function calls, and Alexandrescu is using it to trick the compiler into failing to compile thread-unsafe code.
I see it as many metaprogramming tricks that are there not because of what they do at compile time, but rather for what it forces the compiler to do for you.
I think the issue is not about thread-safety provided by volatile. It dosen't and Andrei's article dosen't say it does. Here, a mutex is used to achieve that. The issue is, whether the use of volatilekeyword to provide static type-checking along with use of mutex for thread-safe code, is abuse of the volatile keyword? IMHO it's pretty smart, but i have come across developers who are not fans of strict-type-checking just for the sake of it.
IMO when you are writing code for multi-threaded environment, there is already enough caution to emphasize wherein you would expect people not to be ignorant of race-conditions and deadlocks.
A downside of this wrapped approach is that every operation on the type that is wrapped using LockingPtr must be through a member function. That will increase one level of indirection which might considerably affect developers comfort in a team.
But if you are a purist who believes in the spirit of C++ a.k.a strict-type-checking; this is a good alternative.
This catches some kinds of thread-unsafe code (concurrent access), but misses others (deadlocks due to locking inversion). Neither is especially easy to test for, so it's a modest partial win. In practice, remembering to enforce a constraint that a particular private member is accessed only under some specified lock, hasn't been a big problem for me.
Two answers to this question have demonstrated that you're correct to say that confusion is a significant disadvantage - maintainers may have been so strongly conditioned to understand that volatile's memory-access semantics have nothing to do with thread-safety, that they will not even read the rest of the code/article before declaring it incorrect.
I think the other big disadvantage, outlined by Alexandrescu in the article, is that it doesn't work with non-class types. This might be a difficult restriction to remember. If you think that marking your data members volatile stops you using them without locking, and then expect the compiler to tell you when to lock, then you might accidentally apply that to an int, or to a member of template-parameter-dependent type. The resulting incorrect code will compile fine, but you may have stopped examining your code for errors of this kind. Imagine the errors which would occur, especially in template code, if it was possible to assign to a const int, but programmers nevertheless expected the compiler would check const-correctness for them...
I think the risk that the data member's type actually has any volatile member functions should be noted and then discounted, although it might bite somebody someday.
I wonder if there's anything to be said for compilers providing additional const-style type modifiers via attributes. Stroustrup says, "The recommendation is to use attributes to only control things that do not affect the meaning of a program but might help detect errors". If you could replace all mentions of volatile in the code with [[__typemodifier(needslocking)]] then I think it would be better. It would then be impossible to use the object without a const_cast, and hopefully you wouldn't write a const_cast without thinking about what it is you're discarding.
C++03 §7.1.5.1p7:
If an attempt is made to refer to an object defined with a volatile-qualified type through the use of an lvalue with a non-volatile-qualified type, the program behaviour is undefined.
Because buffer_ in your example is defined as volatile, casting it away is undefined behavior. However, you can get around that with an adapter which defines the object as non-volatile, but adds volatility:
template<class T>
struct Lock;
template<class T, class Mutex>
struct Volatile {
Volatile() : _data () {}
Volatile(T const &data) : _data (data) {}
T volatile& operator*() { return _data; }
T const volatile& operator*() const { return _data; }
T volatile* operator->() { return &**this; }
T const volatile* operator->() const { return &**this; }
private:
T _data;
Mutex _mutex;
friend class Lock<T>;
};
The friendship is needed to strictly control non-volatile access through an already locked object:
template<class T>
struct Lock {
Lock(Volatile<T> &data) : _data (data) { _data._mutex.lock(); }
~Lock() { _data._mutex.unlock(); }
T& operator*() { return _data._data; }
T* operator->() { return &**this; }
private:
Volatile<T> &_data;
};
Example:
struct Something {
void action() volatile; // Does action in a thread-safe way.
void action(); // May assume only one thread has access to the object.
int n;
};
Volatile<Something> data;
void example() {
data->action(); // Calls volatile action.
Lock<Something> locked (data);
locked->action(); // Calls non-volatile action.
}
There are two caveats. First, you can still access public data members (Something::n), but they will be qualified volatile; this will probably fail at various points. And second, Something doesn't know if it really has been defined as volatile and casting away that volatile (from "this" or from members) in methods will still be UB if it has been defined that way:
Something volatile v;
v.action(); // Compiles, but is UB if action casts away volatile internally.
The main goal is achieved: objects don't have to be aware that they are used this way, and the compiler will prevent calls to non-volatile methods (which is all methods for most types) unless you explicitly go through a lock.
Building on other code and removing the need for the volatile specifier entirely, this not only works, but correctly propagates const (similar to iterator vs const_iterator). Unfortunately, it requires quite a bit of boilerplate code for the two interface types, but you don't have to repeat any logic of methods: each is still defined once, even if you do have to "duplicate" the "volatile" versions similarly to normal overloading of methods on const and non-const.
#include <cassert>
#include <iostream>
struct ExampleMutex { // Purely for the sake of this example.
ExampleMutex() : _locked (false) {}
bool try_lock() {
if (_locked) return false;
_locked = true;
return true;
}
void lock() {
bool acquired = try_lock();
assert(acquired);
}
void unlock() {
assert(_locked);
_locked = false;
}
private:
bool _locked;
};
// Customization point so these don't have to be implemented as nested types:
template<class T>
struct VolatileTraits {
typedef typename T::VolatileInterface Interface;
typedef typename T::VolatileConstInterface ConstInterface;
};
template<class T>
class Lock;
template<class T>
class ConstLock;
template<class T, class Mutex=ExampleMutex>
struct Volatile {
typedef typename VolatileTraits<T>::Interface Interface;
typedef typename VolatileTraits<T>::ConstInterface ConstInterface;
Volatile() : _data () {}
Volatile(T const &data) : _data (data) {}
Interface operator*() { return _data; }
ConstInterface operator*() const { return _data; }
Interface operator->() { return _data; }
ConstInterface operator->() const { return _data; }
private:
T _data;
mutable Mutex _mutex;
friend class Lock<T>;
friend class ConstLock<T>;
};
template<class T>
struct Lock {
Lock(Volatile<T> &data) : _data (data) { _data._mutex.lock(); }
~Lock() { _data._mutex.unlock(); }
T& operator*() { return _data._data; }
T* operator->() { return &**this; }
private:
Volatile<T> &_data;
};
template<class T>
struct ConstLock {
ConstLock(Volatile<T> const &data) : _data (data) { _data._mutex.lock(); }
~ConstLock() { _data._mutex.unlock(); }
T const& operator*() { return _data._data; }
T const* operator->() { return &**this; }
private:
Volatile<T> const &_data;
};
struct Something {
class VolatileConstInterface;
struct VolatileInterface {
// A bit of boilerplate:
VolatileInterface(Something &x) : base (&x) {}
VolatileInterface const* operator->() const { return this; }
void action() const {
base->_do("in a thread-safe way");
}
private:
Something *base;
friend class VolatileConstInterface;
};
struct VolatileConstInterface {
// A bit of boilerplate:
VolatileConstInterface(Something const &x) : base (&x) {}
VolatileConstInterface(VolatileInterface x) : base (x.base) {}
VolatileConstInterface const* operator->() const { return this; }
void action() const {
base->_do("in a thread-safe way to a const object");
}
private:
Something const *base;
};
void action() {
_do("knowing only one thread accesses this object");
}
void action() const {
_do("knowing only one thread accesses this const object");
}
private:
void _do(char const *restriction) const {
std::cout << "do action " << restriction << '\n';
}
};
int main() {
Volatile<Something> x;
Volatile<Something> const c;
x->action();
c->action();
{
Lock<Something> locked (x);
locked->action();
}
{
ConstLock<Something> locked (x); // ConstLock from non-const object
locked->action();
}
{
ConstLock<Something> locked (c);
locked->action();
}
return 0;
}
Compare class Something to what Alexandrescu's use of volatile would require:
struct Something {
void action() volatile {
_do("in a thread-safe way");
}
void action() const volatile {
_do("in a thread-safe way to a const object");
}
void action() {
_do("knowing only one thread accesses this object");
}
void action() const {
_do("knowing only one thread accesses this const object");
}
private:
void _do(char const *restriction) const volatile {
std::cout << "do action " << restriction << '\n';
}
};
Look at this from a different perspective. When you declare a variable as const, you are telling the compiler that the value cannot be changed by your code. But that doesn't mean that the value won't change. For example, if you do this:
const int cv = 123;
int* that = const_cast<int*>(&cv);
*that = 42;
...this evokes undefined behavior according to the standard, but in practice something will happen. Maybe the value will be changed. Maybe there will be a sigfault. Maybe flight simulator will launch -- who knows. The point is you don't know on a platform-independant basis what's going to happen. So the apparent promise of const is not fulfilled. The value may or may not actually be const.
Now, given that this is true, is using const an abuse of the language? Of course not. It is still a tool that the language provides to help you write better code. It will never be the end-all, be-all tool to ensure that values remain unchanged -- the programmer's brain is ultimately that tool -- but does that make const unuseful?
I say no, using const as a tool to help you write better code is not an abuse of the language. In fact I'd go one step further, and say it is the intent of that feature.
Now, the same is true of volatile. Declaring something as volatile will not make your program thread safe. It probably won't even make that variable or object thread safe. But the compiler will enforce CV-qualification semantics, and careful programmer can leverage this fact to help him write better code by helping the compiler to identify places where he might be writing a bug. Just like the compiler helps him when he tries to do this:
const int cv = 123;
cv = 42; // ERROR - compiler complains that the programmer is potentially making a mistake
Forget about memory fences and atomicity of volatile objects and variables, just like you have long forgotten about cv's true constness. But use the tools that the language gives you to write better code. One of those tools is volatile.
You must better not do that. volatile was not even invented to provide thread-safety. It was invented to access memory-mapped hardware registers properly. volatile keyword has no effect over CPU's out-of-order execution feature. You should use proper OS calls or CPU defined CAS instructions, memory fences, etc.
CAS
Memory Fence
In the article the keyword is used more like a required_thread_safety tag than the actual intended use of volatile.
Without having read the article – why isn’t Andrei using said required_thread_safety tag then? Abusing volatile doesn’t sound such a good idea here. I believe this causes more confusion (like you said), rather than avoiding it.
That said, volatile may sometimes be required in multi-threaded code even if it’s not a sufficient condition, just to prevent the compiler from optimizing away checks that rely on asynchronous update of a value.
I don't know specifically whether Alexandrescu's advice is sound, but, for all that I respect him as a super-smart dude, his treatment of volatile's semantics suggests that he's stepped way outside his area of expertise. Volatile has absolutely no value in multithreading (see here for a good treatment of the subject) and so Alexandrescu's claim that volatile is useful for multithreaded access leads me to seriously wonder how much faith I can place in the rest of his article.
Is there any template available in boost for RAII. There are classes like scoped_ptr, shared_ptr which basically work on pointer. Can those classes be used for any other resources other than pointers. Is there any template which works with a general resources.
Take for example some resource which is acquired in the beginning of a scope and has to be somehow released at the end of scope. Both acquire and release take some steps. We could write a template which takes two(or maybe one object) functors which do this task. I havent thought it through how this can be achieved, i was just wondering are there any existing methods to do it
Edit: How about one in C++0x with support for lambda functions
shared_ptr provides the possibility to specify a custom deleter. When the pointer needs to be destroyed, the deleter will be invoked and can do whatever cleanup actions are necessary. This way more complicated resources than simple pointers can be managed with this smart pointer class.
The most generic approach is the ScopeGuard one (basic idea in this ddj article, implemented e.g. with convenience macros in Boost.ScopeExit), and lets you execute functions or clean up resources at scope exit.
But to be honest, i don't see why you'd want that. While i understand that its a bit annoying to write a class every time for a one-step-aquire and one-step-release pattern, you are talking about multi-step-aquire and -release.
If its taken multiple steps, it, in my opinion, belongs in an appropiately named utility class so that the details are hidden and the code in place (thus reducing error probability).
If you weigh it against the gains, those few additional lines are not really something to worry about.
A more generic and more efficient (no call through function pointer) version is as follows:
#include <boost/type_traits.hpp>
template<typename FuncType, FuncType * Func>
class RAIIFunc
{
public:
typedef typename boost::function_traits<FuncType>::arg1_type arg_type;
RAIIFunc(arg_type p) : p_(p) {}
~RAIIFunc() { Func(p_); }
arg_type & getValue() { return p_; }
arg_type const & getValue() const { return p_; }
private:
arg_type p_;
};
Example use:
RAIIFunc<int (int), ::close> f = ::open("...");
I have to admit I don't really see the point. Writing a RAII wrapper from scratch is ridiculously simple already. There's just not much work to be saved by using some kind of predefined wrapper:
struct scoped_foo : private boost::noncopyable {
scoped_foo() : f(...) {}
~scoped_foo() {...}
foo& get_foo() { return f; }
private:
foo f;
};
Now, the ...'s are essentially the bits that'd have to be filled out manually if you used some kind of general RAII template: creation and destruction of our foo resource. And without them there's really not much left. A few lines of boilerplate code, but it's so little it just doesn't seem worth it to extract it into a reusable template, at least not at the moment. With the addition of lambdas in C++0x, we could write the functors for creation and destruction so concisely that it might be worth it to write those and plug them into a reusable template. But until then, it seems like it'd be more trouble than worth. If you were to define two functors to plug into a RAII template, you'd have already written most of this boilerplate code twice.
I was thinking about something similar:
template <typename T>
class RAII {
private:
T (*constructor)();
void (*destructor)(T);
public:
T value;
RAII(T (*constructor)(), void (*destructor)(T)) :
constructor(constructor),
destructor(destructor) {
value = constructor();
}
~RAII() {
destructor(value);
}
};
and to be used like this (using OpenGL's GLUquadric as an example):
RAII<GLUquadric*> quad = RAII<GLUquadric*>(gluNewQuadric, gluDeleteQuadric);
gluSphere(quad.value, 3, 20, 20)
Here's yet another C++11 RAII helper: https://github.com/ArtemGr/libglim/blob/master/raii.hpp
It runs a C++ functor at destruction:
auto unmap = raiiFun ([&]() {munmap (fd, size);});