6

When implementing condition variables into a Win32 C++ program, would it be better to use Win32 functions, classes, and data types (e.g. CreateThread, SleepConditionVariableCS, WaitForSingleObjectEx, ReleaseMutex, CONDITION_VARIABLE) or those from the C++11 standard libraries (e.g. thread, wait, join, unlock, condition_variable)?

Since the answer to this question is probably not binary, what considerations should one take into account when making such a decision?

Cerran
  • 2,087
  • 2
  • 21
  • 33
  • 3
    Given that visual studio isn't done implementing the standard, if portability isn't an issue, I'd use the windows calls for now. – woolstar Jan 27 '14 at 16:11
  • Functions have preconditions and postconditions. When you write software, you have "purposes". Functions may satisfy your purposes or not, but they are not "better" or "worse". They are just functions. – Daniel Daranas Jan 27 '14 at 16:12
  • @woolstar I'm actually using Code::Blocks and the latest version of MinGW, but that's a good consideration. – Cerran Jan 27 '14 at 16:16
  • Do you ever plan to be cross-platform? – Chad Jan 27 '14 at 16:16
  • @Chad Of course you're right, a desire for (even potential) cross-platform functionality would make the decision clear; I'm wondering what else should be considered (assuming portability is irrelevant). – Cerran Jan 27 '14 at 16:23
  • @DanielDaranas Correct. That's a point I already addressed in the final sentence of my question. I don't know what potential benefits either set of functions may have. – Cerran Jan 27 '14 at 16:26
  • 1
    In some cases there isn't a like-for-like comparison. `CreateEvent()` for instance, can be replicated with a `std::condition_varaible`, but the underlying implementation is different enough that there can be performance differences when trying to use the constructs. – Chad Jan 27 '14 at 17:28

2 Answers2

6

The C++ synchronization mechanisms are designed to C++ principles. They free their resources in the destructor, and they also use RAII to ensure safe locking. They use exceptions to signal errors.

Essentially, they are much harder to use incorrectly than the function-based native Windows API. This means that if you can use them (your implementation supports them), you always should use them.

Oh, and they are cross-platform.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • I completely agree. If you ever need the native handles of those objects, use the `native_handle()` method, with the understanding that the native handle may not be always available, or it may not be what you think it is. For example, a mutex in the C++11 library implementation may use an atomic variable for the uncontested case, so there won't be a native handle available for anything unless the mutex is contested. – Kuba hasn't forgotten Monica Jan 27 '14 at 16:24
  • 1
    A small note on the side: VC2012's implementation of the thread library has quite a few bugs left which can leave you with ugly race conditions. So unless you are already working with VC2013, consider using [Boost's implementation of the thread library](http://www.boost.org/doc/libs/1_55_0/doc/html/thread.html) instead, which is much more mature. You shouldn't notice any difference in performance between the two, as they are both rather thin wrappers around the native Win32 functions. – ComicSansMS Jan 27 '14 at 16:26
  • Whether they're cross-platform or not is irrelevant if the program already contains other Win32 code though, right? Unless portions of the code might possibly be re-purposed into portable code. Of course, the advantage of me learning one or the other is that the resulting knowledge could be cross-platform. – Cerran Jan 27 '14 at 16:36
  • Yeah. You learn the cross-platform code, you can reuse the parts that are cross-platform, and you have less work if you ever want to port. – Sebastian Redl Jan 27 '14 at 17:46
  • Indeed, after further research and implementing my own condition variable, I now understand that the use of RAII and exceptions in C++ Standard Library classes such as `thread`, `mutex`, and `condition_variable` is quite well done and makes handling errors simpler than handling errors in Win32 functions. Also, once you understand these classes, they're surprisingly easy to use. – Cerran Feb 04 '14 at 10:26
1

One consideration should be what your compiler can handle. For example, when you install MinGW on Windows, you can choose whether to install the API for POSIX threads or Win32 threads. On the other hand, if you use TDM-GCC, you should be aware that versions 4.7.1 and lower use Win32 threads, while versions 4.8.1 and higher use POSIX threads. And as woolstar mentioned above, if you're using Microsoft's compiler, you should check to see whether the bugs in its support for these classes have been worked out.

If your compiler supports POSIX threads, you can use the C++ thread classes of the Standard Library (e.g. thread, mutex, condition_variable). If your compiler supports Win32 threads, you can use the Win32 thread functions.

In my case, I originally had TDM-GCC 4.7.1 and tried to use the C++ Standard Library classes, but that didn't work (for reasons explained above). So I installed MinGW by itself and chose "posix" in the "threads" option of the installer. Then I was able to use those classes.

Cerran
  • 2,087
  • 2
  • 21
  • 33