What are the advantages and disadvantages of using Interlocked winapi functions instead of any library provides atomic operations on Win32 platform?
Portability is not an issue.
If portability is not a concern then you're basically down to deciding whom you trust more to get this right. A library is generally designed to provide portability. It otherwise has a tough time competing with an OS provided implementation that's been battle-hardened for over 15 years.
Check this thread to see an example of how the obvious implementation is not in fact the best.
The Interlocked winapi functions work on old processors even when there is no CPU support for locked operations. 386 and maybe 486, not really a issue today unless you still support Win9x and older NT.
It would likely depend up on the specific atomic library in question.
A good library with a specific back-end would likely end up with the same implementation of a couple of ASM instructions to issue an x86 lock instruction and do their work. And assuming the library itself is portable, subsequently make your code portable.
A naive atomic implementation might do something heavier like use a mutex to protect a normal variable. I don't know of any that do - just making the point for argument.
As such, given your stated non-portability requirements, using the Win32 functions should be fine. Alternately, go ahead with an Atomic version, but perhaps look at the actual implementation.
Related
I searched for lots of questions and answers, but I really couldn't figure out this issue. Yesterday I have tried C++11 thread on Windows in a Visual C++ project and it works fine.
Does that mean we can use C++11 threads on every platform that has a compiler with C++11 support? Are there any reasons not to use this thread instead of pthread or Windows thread (depending on the platform)?
The C++ 11 thread library still uses threads from the OS and relies on them but it is abstracted in a good way so you will experience almost no differences. The behavior is different only in the detail and you will almost not notice them (only on edge cases and/or on failure). There might be still some platforms out there which don't support everything from std::thread (even in 2015, e.g. on some specific / exotic mobile platforms).
From the C++ Standard:
30 Thread support library
Some functions described in this Clause are specified to throw
exceptions of type system_error (19.5.6). Such exceptions shall be
thrown if any of the function’s error conditions is detected or a call
to an operating system or other underlying API results in an error
that prevents the library function from meeting its specifications.
Failure to allocate storage shall be reported as described in
17.6.5.12.
C++11's thread mechanisms are intended to be cross-platform like any other feature of standard C++. From my understanding, all major compilers intend to support the C++ standard to the best of their ability which means supporting the threading library.
It really depends how well the compiler supports it. I would imagine GCC / VS /Intel have pretty good support by now but then if you are targeting some exotic platform that might not necessarily be the case.
That's been the case with the STL for a while now - it's mostly portable, but it really depends on the implementation.
Just because it's in the standard does not mean it will magically work, even though the chance of it working is much higher than if it was not in the standard.
There will still be other implementations - pthread, boost, whatever. Which one you use depends on your personal preferences, your requirements, etc, etc.
Yes, it is platform independent. It can be (and often is) implemented as wrapper for pthreads, so basically it can be pthreads with different API.
Why is it that threads were never included as part of the C++ standard originally? Did they not exist when C++ standard was first created?
I think the main reasons are
specifying threading behavior into the language needs a lot of work and understanding, which nobody had available back then
nobody had a great idea about a good threading API, and there was no one existing library that seemed good enough to be used as a base for further work
the standardization committee was swamped with enough of other work (like incorporating the STL into the standard library)
that standard was late as it was; it took more than ten years for the first version to emerge, with quite a lot delay due to "last-minute changes" (std::auto_ptr, STL), and I think the main feeling was to better have something out sooner than to keep waiting for an infinitively delayed perfect standard; I think back then most people didn't think it would take so long for the next version to get finalized
After the standard was ratified, boost was founded by members of the library working group as a testbed for libraries which were desirable to have in the std lib but for which there wasn't enough time to make it for the final version. There, much of the work needed for adding threading support to C++ (namely inventing a good threading library) was done.
The current Standard is from 1998. There were different thread implementations, and there wasn't the body of experience with using threads that there is twelve years later. If C++ had had a standardized thread library, it would likely have worked poorly with some common thread implementations, and might well have been difficult to adapt in the future.
It's twelve years later now, and we know a whole lot more about how threads are used, and the more widespread use created more interest in standardizing them, so the upcoming C++ standard (which I hope will be official in 2011) will have a section on threads in the library.
Threads certainly did exist when C++ was being standardised during the 1990s. However, Windows and Posix have very different threading APIs. Designing a library of the quality you'd want from a standard language library, giving all the threading primitives you need and mapping well onto both popular APIs (and others), required a large effort. Including it in the initial standard would have required either delaying standardisation, possibly for years, or including a specification that may well have had significant shortcomings.
That work has been done over the last decade or so (initially as the Boost.Thread library), and will be included as the standard thread support library in the next version of the standard, in addition to language-level features such as thread-local storage.
There is a lot of work involved in creating a thread class and C++0x has largely addressed this by adding the thread, mutex and atomic libraries but it took a lot of work from a lot of folks.
Orginazationally, remember that C++ is a very large language and changes happen quite slowly to it because of the complexity of the language and the amount of code and industry that rely on it; it takes a long time to get ratify changes into the standard because of this.
Also threading and synchronization has typically been an OS provided functionality so any additions needed to be compatible with the common implementations and possible without massive changes to the platforms (or noone would be able to implement the standard).
Technically, it isn't sufficient to just add a thread API, C++ was also missing a cohesive memory model, i.e. how do variables interact across thread and how do we allow for the wide range of memory models to be expressed in code succinctly (and performantly). Most of us are fortunate enough to work on primarily single-threaded x86 based software which has a very forgiving memory model, but there is other hardware out there that is not as forgiving from a memory model perspective and where performance penalties can be quite harsh.
The library addresses the memory model issue by providing atomic variables with forgiving defaults and explicit control.
The library provides another key piece of functionality for portable threading by providing synchronization classes.
Finally was added and if you haven't read the history on the working group site, it's interesting, but simply replacing CreateThread, QueueUserWorkItem or a pthread invocation was a thread object isn't quite enough. Thread lifetime, state management and thread local storage all had to be thought through.
All of this took a long time to get right and as others have mentioned most of it was in boost for quite awhile to ensure that major issues were worked through and it was cohesive before making it into the new standard.
Because the authors didn't want to force a particular behaviour on implementers.
Threads are an OS thing, so they aren't really a function of the programming language as much as they are the libraries provided by the system. POSIX threads for example, can be used in C++ but aren't really "part" of it.
One of the challenges that was faced by the standard committee 12 years ago is the differences in the parallel hardware. A key distinguishing feature between various high performance computing architectures is the way the permit parallel computation, and only one of those many models is really similar to the posix threads abstraction, SMP.
If you compare this situation to the one faced by the Fortran language, which targets this sort of hardware specifically, you see that each vendor supplies a Fortran compiler that they have extended to support the special parallel computing features the hardware provides.
This can be seen as relevant in todays terms by comparing typical x86/x64 white box compute nodes, which usually have up to 4 sockets, which translates into 24 cores with a single shared memory to a Gaming PC with multiple nVidia or AMD GPU's. Both are capable of startling compute throughput, but to get the most out of either requires a very different programming style. In fact, different workloads will work significantly better on one architecture than the other, depending on the exact nature of the specific algorithm.
That being said, it was probably impossible, 12 years ago, for the standard committee to identify how it should address each of these issues. Now, however, the answer is much simpler. C++ is not aimed at anything besides SMP hardware; those are served by other languages and tool-chains such as OpenCL or VHDL.
Because they are OS dependent. I.E. unix/linux/macosx use pthread API, Windows use its own API, and so on and so forth...
They could have been included into libstdc++, but I guess it is not easy to include all current and future thread features on a common API. The same way, DB access is not included in libstdc++ either.
With the advent of threading facilities in the STL for the new C++ standard (C++0x), will it be better to change existing code that is using POSIX threading or even Windows threading to use STL threading?
You could always hedge your bets... write your own simple threading API that is just featureful enough to do what your application needs to be done, and change your code to target your threading API only. Then you can implement the internals of your custom threading API using Windows or Posix or STL or whatever, and change the implementation whenever you need to without having to touch your entire codebase each time.
By doing it that way, you could start with the STL implementation, and then if it turns out that e.g. Windows has a difficult-to-resolve problem using that, you could just include an alternate Windows-API implementation inside my_threading_api.cpp (inside of an #ifdef WIN32) and you'd be back in business.
A great deal will depend on how much you care about portability, and how much you're taking advantage of features your native API may provide that the standard library doesn't. The standard library threading is sufficiently similar to POSIX that (at least offhand) I can't think of much you'd gain by staying with POSIX (and due to the similarity, porting to use the standard library should usually be pretty easy).
Windows threading is enough different that you're more likely to run into something that will be non-trivial to port to using the standard library, and even at best porting will probably be non-trivial.
Don't change unless you really need it. I assume that your existing code is working well.
There's no telling how long it will be before the C++0x library features are commonly supported, so the answer might well depend on how tied to a particular compiler you might want to be.
You might also want to consider a framework or library that works on top of the native or C++0x library implementation, such as Boost Threads or the Intel Threading Building Blocks and let that library handle the details of whether it's using C++0x features or platform APIs.
It depends.
C++0x threading isn't widely supported yet (I think GCC implements it, but MSVC doesn't, and I don't know when they're planning to add that support, but I might suspect they consider it a low priority feature)
If your code works as it is, why change it?
For new C++ applications, and assuming compiler support, I'd go with C++0x threads, simply because they're standard, and it's a much nicer API than either Win32 or POSIX threads.
How to write a Reader/Writer lock with timeout, using conditional variables in C/C++?
If you're just looking for a library, Boost.Thread might do what you want.
You may take a look at the source of Java's implementation ReentrantReadWriteLock.
Just grab the JDK unpack the src.zip file and search for the source.
There is no support for such things in current standard C++, although C++0x will have some threading support (I haven't checked to see how much). Therefore, any answer would have to be platform-dependent, using platform in a very general sense.
It is possible to write libraries that will behave similarly across different underlying systems, and there are quite a few cross-platform libraries. (These are subject to inefficiencies, of course, if the capabilities of the underlying platforms are different.) There could be a generally accepted C++ threading library that would work on Windows and Unix-based systems (which is almost anything you'd be running on a desktop nowadays), but I don't know of one offhand.
Therefore, this question can't really be answered as asked. It would be necessary to answer it on a particular platform or library, and none is specified. It would make sense if coupled with a request for a library recommendation.
Take a look at the Boost.Thread library. Specifically: shared_mutex and upgradeable_mutex objects.
In a C++ Linux app, what is the simplest way to get the functionality that the Interlocked functions on Win32 provide? Specifically, a lightweight way to atomically increment or add 32 or 64 bit integers?
Just few notes to clarify the issue which has nothing to do with Linux.
RWM (read-modify-write) operations and those that do not execute in a single-step need the hardware-support to execute atomically; among them increments and decrements, fetch_and_add, etc.
For some architecture (including I386, AMD_64 and IA64) gcc has a built-in support for atomic memory access, therefore no external libray is required. Here you can read some information about the API.
Intel's open-source ThreadBuildingBlocks has a template, Atomic, that offers the same functionality as .NET's Interlocked class.
Unlike gcc's Atomic built-ins, it's cross platform and doesn't depend on a particular compiler. As Nemanja Trifunovic correctly points out above, it does depend on the compare-and-swap CPU instruction provided by x86 and Itanium chips. I guess you wouldn't expect anything else from an Intel library : )
Strictly speaking, Linux cannot offer atomic "interlocked" functions like ones in Win32, simply because these functions require hardware support, and Linux runs on some platforms that don't offer that support. Having said that, if you can constrain yourself to Intel x86/x64, take a look at the implementation of reference counting in Boost shared pointers library.
The atomic functions from the Apache Portable Runtime are really close to the Win32 InterlockedXXX functions.
You can insert some assembly code in your source, to use x68 interlocked instructions directly.
You should use a lock xadd operation.
See for instance this.
The fairly common glib library that's used in GTK and QT programming as well as standalone offers a variety of atomic operations. See http://library.gnome.org/devel/glib/2.16/glib-Atomic-Operations.html for a list. There are g_atomic functions for most of the operations that Interlocked supports on Win32, and on platforms where the hardware directly supports these, they are inlined as the needed assembly code.
Upon further review, this looks promising. Yay stack overflow.