People use singleton everywhere. Read some threads recently from stackoverflow that singleton should be avoided in C++, but not clear why is that.
Some might worry about memory leak with undeleted pointers, things such as exceptions will skip the memory recycle codes. But will the auto_ptr solve this problem?
In general, as mentioned in another answer, you should avoid mutable global data. It introduces a difficulty in tracking code side effects.
However your question is specifically about C++. You could, for instance, have global immutable data that is worth sharing in a singleton. In C++, specifically, it's nearly impossible to safely initialize a singleton in a multithreaded environment.
Multithreaded Environment
You can use the "construct on first use" idiom to make sure the singleton is properly initialized exactly by the time it is needed: http://www.parashift.com/c++-faq-lite/static-init-order.html.
However, what happens if you have 2 (or more) threads which all try to access the singleton for the first time, at exactly the same time? This scenario is not as far fetched as it seems, if the shared immutable data is data required by your calculateSomeData thread, and you initialize several of these threads at the same time.
Reading the discussion linked above in the C++ FAQ Lite, you can see that it's a complex question in the first place. Adding threads makes it much harder.
On Linux, with gcc, the compiler solves this problem for you - statics are initialized within a mutex and the code is made safe for you. This is an enhancement, the standard requires no such behavior.
In MSVC the compiler does not provide this utility for you and you get a crash instead. You may think "that's ok, I'll just put a mutex around my first use initialization!" However, the mutex itself suffers from exactly the same problem, itself needing to be static.
The only way to make sure your singleton is safe for threaded use is to initialize it very early in the program before any threads are started. This can be accomplished with a trick that causes the singleton to be initialized before main is called.
Singletons That Rely on Other Singletons
This problem can be mostly solved with the construct on first use idiom, but if you have the problem of initializing them before any threads are initialized, you can potentially introduce new problems.
Cross-platform Compatibility
If you plan on using your code on more than one platform, and compile shared libraries, expect some issues. Because there is no C++ ABI interface specified, each compiler and platform handles global statics differently. For instance, unless the symbols are explicitly exported in MSVC, each DLL will have its own instance of the singleton. On Linux, the singletons will be implicitly shared between shared libraries.
Avoid mutable global variables whether they're singletons or not, since they introduce unconstrained lines of communication: you don't know what part of the code is affecting what other parts, or when that happens.
Related
I am writing a firmware for an esp32 in C++ and I found it to be awesome to pass an object reference as parameter when registering an ISR because I can simply delegate the work from the ISR to the specific object (a resource in this case), managing the resource properties and functionality directly from the class. However, I'm not exactly sure what to look out for when using this technique.
Is there anything inherently wrong with it?
If not, what should one be aware of when doing it?
Is there anything wrong with passing “this” as an argument to ISR registration?
No.
Is there anything inherently wrong with it?
No.
If not, what should one be aware of when doing it?
Object lifetime. Compiler optimization. Resource sharing. Locking. Atomic access. Specific hardware semantics. Additionally, esp32 is a two core platform. The list could go on and there are many books about programming on esp32, about programming in parallel environments and sharing resources between main part of code and interrupt routines. One should be aware of all such programming related topics and also about good code conventions, naming and C++ language.
I can simply delegate the work from the ISR to the specific object (a resource in this case), managing the resource properties and functionality directly from the class.
This is already wrong. In case you do write a driver in the form of a class for a particular hardware peripheral, then the ISR should be inside that class as a static member function. Or at very least reside in the same translation unit as a static function, but that kind of defeats the purpose of using a class to begin with.
If you design the program like that though, then sure you can pass a reference to that class.
Is there anything inherently wrong with it?
Apart from the above, then yeah this must be a singleton object with static storage duration. And using static storage duration objects of C++ classes is inherently wrong in embedded systems, because these will be called by the CRT during microcontroller start-up. Which in turn causes all such C++ programs to start slower than the C equivalent.
But also in this particular case, if the interrupt needs to be started in a timely fashion from the point of power-on reset, then C++ object initialization will not provide that necessary real-time performance. This makes C++ classes unsuitable for interrupts like watchdogs, low-voltage warnings, clock monitor, CPU exceptions and other critical hardware interrupts.
If not, what should one be aware of when doing it?
The usual re-entrancy problems that appears when you communicate between an ISR and the caller program. This re-entrancy mechanism can be encapsulated in the class.
And as usual, the variables involved in this may need to be volatile qualified to prevent incorrect compiler optimizations, depending on how dumb your compiler is. This has nothing to do with re-entrancy. See Using volatile in embedded C development.
Thread-safe or thread-compatible code is good.
However there are cases in which one could implement things differently (more simply or more efficiently) if one knows that the program will not be using threads.
For example, I once heard that things like std::shared_ptr could use different implementations to optimize the non-threaded case (but I can't find a reference).
I think historically std::string in some implementation could use Copy-on-write in non-threaded code.
I am not in favor or against these techniques but I would like to know if that there is a way, (at least a nominal way) to determine at compile time if the code is being compiled with the intention of using threads.
The closest I could get is to realize that threaded code is usually (?) compiled with the -pthreads (not -lpthreads) compiler option.
(Not sure if it is a hard requirement or just recommended.)
In turn -pthreads defines some macros, like _REENTRANT or _THREAD_SAFE, at least in gcc and clang.
In some some answers in SO, I also read that they are obsolete.
Are these macros the right way to determine if the program is intended to be used with threads? (e.g. threads launched from that same program). Are there other mechanism to detect this at compile time? How confident would the detection method be?
EDIT: since the question can be applied to many contexts apparently, let me give a concrete case:
I am writing a header only library that uses another 3rd party library inside. I would like to know if I should initialize that library to be thread-safe (or at least give a certain level of thread support). If I assume the maximum level of thread support but the user of the library will not be using threads then there will be cost paid for nothing. Since the 3rd library is an implementation detail I though I could make a decision about the level of thread safety requested based on a guess.
EDIT2 (2021): By chance I found this historical (but influential) library Blitz++ which in the documentation says (emphasis mine)
8.1 Blitz++ and thread safety
To enable thread-safety in Blitz++, you need to do one of these
things:
Compile with gcc -pthread, or CC -mt under Solaris. (These options define_REENTRANT,which tells Blitz++ to generate thread-safe code).
Compile with -DBZ_THREADSAFE, or #define BZ_THREADSAFE before including any Blitz++ headers.
In threadsafe mode, Blitz++ array reference counts are safeguarded by
a mutex. By default, pthread mutexes are used. If you would prefer a
different mutex implementation, add the appropriate BZ_MUTEX macros to
<blitz/blitz.h> and send them toblitz-dev#oonumerics.org for
incorporation. Blitz++ does not do locking for every array element
access; this would result in terrible performance. It is the job of
the library user to ensure that appropriate synchronization is used.
So it seems that at some point _REENTRANT was used as a clue for the need of multi-threading code.
Maybe it is a very old reference to take seriously.
I support the other answer in that thread-safety decision ideally should not be done on whole program basis, rather they should be for specific areas.
Note that boost::shared_ptr has thread-unsafe version called boost::local_shared_ptr. boost::intrusive_ptr has safe and unsafe counter implementation.
Some libraries use "null mutex" pattern, that is a mutex, which does nothing on lock / unlock. See boost or Intel TBB null_mutex, or ATL CComFakeCriticalSection. This is specifically to substitute real mutex for threqad-safe code, and a fake one for thread-unsafe.
Even more, sometimes it may make sense to use the same objects in thread-safe and thread-unsafe way, depending on current phase of execution. There's also atomic_ref which serves the purpose of providing thread-safe access to underlying type, but still letting work with it in thread unsafe.
I know a good example of runtime switches between thread-safe and thread-unsafe. See HeapCreate with HEAP_NO_SERIALIZE, and HeapAlloc with HEAP_NO_SERIALIZE.
I know also a questionable example of the same. Delphi recommends calling its BeginThread wrapper instead of CreateThread API function. The wrapper sets a global variable telling that from now on Delphi Memory Manager should be thread-safe. Not sure if this behavior is still in place, but it was there for Delphi 7.
Fun fact: in Windows 10, there are virtually no single-threaded programs. Before the first statement in main is executed, static DLL dependencies are loaded. Current Windows version makes this DLL loading paralleled where possible by using thread pool. Once program is loaded, thread pool threads are waiting for other tasks that could be issued by using of Windows API calls or std::async. Sure if program by itself will not use threads and TLS, it will not notice, but technically it is multi-threaded from the OS perspective.
How confident would the detection method be?
Not really. Even if you can unambiguously detect if code is compiled to be used with multiple threads, not everything must be thread safe.
Making everything thread-safe by default, even though it is only ever used only by a single thread would defeat the purpose of your approach. You need more fine grainded control to turn on/off thread safety if you do not want to pay for what you do not use.
If you have class that has a thread-safe and a non-thread-safe version then you could use a template parameter
class <bool isThreadSafe> Foo;
and let the user decide on a case for case basis.
First of all, I'm fairly experienced with C++ and understand the basics of threading and thread synchronization. I also want to write a custom memory allocator as a pet project of mine and have read that they should be thread-safe.
I understand what the term "thread-safe" means, but I have no idea on how to make C++ code thread-safe.
Are there any practical examples or tutorials on how to make code thread-safe?
In a memory allocator scenario, is it essentially ensuring that all mutating functions are marked as critical sections? Or is there something more to it?
Same as all threading issues: make sure that when one thread is changing something, no other thread is accessing it. For a memory allocation system, I would imagine you would need a way of making sure you don't allocate the same block of memory to 2 threads at the same time. Whether that is by wrapping the entire search, or by allowing multiple searches but locking when the allocation table is to be updated (which could then cause the result of the search to become invalid, necessitating another search) would be up to you.
I need several STL containers, threadsafe.
Basically I was thinking I just need 2 methods added to each of the STL container objects,
.lock()
.unlock()
I could also break it into
.lockForReading()
.unlockForReading()
.lockForWriting()
.unlockForWriting()
The way that would work is any number of locks for parallel reading are acceptable, but if there's a lock for writing then reading AND writing are blocked.
An attempt to lock for writing waits until the lockForReading semaphore drops to 0.
Is there a standard way to do this?
Is how I'm planning on doing this wrong or shortsighted?
This is really kind of bad. External code will not recognize or understand your threading semantics, and the ease of availability of aliases to objects in the containers makes them poor thread-safe interfaces.
Thread-safety occurs at design time. You can't solve thread safety by throwing locks at the problem. You solve thread safety by not having two threads writing to the same data at the same time- in the general case, of course. However, it is not the responsibility of a specific object to handle thread safety, except direct threading synchronization primitives.
You can have concurrent containers, designed to allow concurrent use. However, their interfaces are vastly different to what's offered by the Standard containers. Less aliases to objects in the container, for example, and each individual operation is encapsulated.
The standard way to do this is acquire the lock in a constructor, and release it in the destructor. This is more commonly know as Resource Acquisition Is Initialization, or RAII. I strongly suggest you use this methodology rather than
.lock()
.unlock()
Which is not exception safe. You can easily forget to unlock the mutex prior to throwing, resulting in a deadlock the next time a lock is attempted.
There are several synchronization types in the Boost.Thread library that will be useful to you, notably boost::mutex::scoped_lock. Rather than add lock() and unlock() methods to whatever container you wish to access from multiple threads, I suggest you use a boost:mutex or equivalent and instantiate a boost::mutex::scoped_lock whenever accessing the container.
Is there a standard way to do this?
No, and there's a reason for that.
Is how I'm planning on doing this
wrong or shortsighted?
It's not necessarily wrong to want to synchronize access to a single container object, but the interface of the container class is very often the wrong place to put the synchronization (like DeadMG says: object aliases, etc.).
Personally I think both TBB and stuff like concurrent_vector may either be overkill or still the wrong tools for a "simple" synchronization problem.
I find that ofttimes just adding a (private) Lock object (to the class holding the container) and wrapping up the 2 or 3 access patterns to the one container object will suffice and will be much easier to grasp and maintain for others down the road.
Sam: You don't want a .lock() method because something could go awry that prevents calling the .unlock() method at the end of the block, but if .unlock() is called as a consequence of object destruction of a stack allocated variable then any kind of early return from the function that calls .lock() will be guaranteed to free the lock.
DeadMG:
Intel's Threading Building Blocks (open source) may be what you're looking for.
There's also Microsoft's concurrent_vector and concurrent_queue, which already comes with Visual Studio 2010.
Soon i'll start working on a parallel version of a mesh refinement algorithm using shared memory.
A professor at the university pointed out that we have to be very careful about thread safety because neither the compiler nor the stl is thread aware.
I searched for this question and the answer depended on the compiler (some try to be somewhat thread-aware) and the plattform (if the system calls used by the compiler are thread-safe or not).
So, in linux, the gcc 4 compiler produces thread-safe code for the new operator?
If not, what is the best way to overcome this problem? Maybe lock each call to the new operator?
You will have to look very hard to find a platform that supports threads but doesn't have a thread safe new. In fact, the thread safety of new (and malloc) is one of the reasons it's so slow.
If you want a thread safe STL on the other hand, you may consider Intel TBB which has thread aware containers (although not all operations on them are thread safe).
Generally the new operator is thread safe - however thread safety guarantees for calls into the STL and the standard library are governed by the standard - this doesn't mean that they are thread unaware - they tend to have very well defined guarantees of thread safety for certain operations. For example iterating through a list in a read-only fashion is thread safe for multiple readers, while iterating through a list and making updates is not. You have to read the documentation and see what the various guarantees are, although they aren't that onerous and they tend to make sense.
While I'm talking about concepts I have not used, I feel I should mention that if you're using shared memory, then you likely want to ensure that you use only POD types, and to use placement new.
Secondly, if you're using shared memory as it is commonly understood to be on linux systems, then you may be using multiple processes - not threads, to allocate memory and 'do stuff' - using shared memory as a communication layer. If this is the case, then the thread safety of your application and libraries are not important - what is important, however, is the thread safety of anything using the shared memory allocation! This is a different situation than running one process with many threads, in which case asking about the thread safety of the new operator IS a valid concern, and could be addressed by placement new if it is not, or by defining your own allocators.
Well, this is not a definitive answer to my question, just that I found out that Google implemented a high-performance multi-threaded malloc.
So, if you're in doubt of whether your implementation is thread safe, maybe you should use the Google Performance Tools.