I find this pretty surprising. Actually, we already use std::mutex and std::recursive_mutex in clang, lld, and other llvm projects, it’s just a coincidence that it hadn’t been introduced into LLVM until my commits.
I’m not sure what the right thing to do here is. If I understand correctly, it seems like in order to encounter this, a) you must be using GCC, b) you must be using the MinGW flavor of GCC, and c) you must be using the threads-win32 flavor of this toolchain. Only if all 3 of those are true, then std::mutex and std::recursive_mutex don’t exist.
Anybody else have thoughts on whether this necessitates reverting the mutex changes, or whether this toolchain configuration should be supported?
I kind of feel like we should drop support for this configuration. Here are the reasons why:
clang, lld, and other LLVM-based tools already make use of std::recursive_mutex and std::mutex, so if those types don’t exist in this one configuration, we have already (even if inadvertently) made a statement that we don’t support that configuration.
We chose C++11 as the baseline because all compilers should support it. This functionality in particular is pretty egregious to not support, considering how simple it is.
Not supporting this configuration does not mean we don’t support GCC / MinGW, it only means we don’t support GCC / MinGW / threads-win32. There is still the threads-posix flavor of this platform which works fine on Windows.
#3 is a little unfortunate and backwards, since on Windows we should be encouraging native Windows implementations of things and discouraging posix emulation, but in this case the functionality just isn’t implemented.
It sounds like this version of libstdc++ doesn’t support std::recursive_mutex from C++11. This is really unfortunate, because we were hoping that moving to C++11 would allow us to use standard, portable threading primitives.
Does this version of MinGW have any C++11 threading support? Is it just recursive_mutex that is missing, or do we have to avoid std::mutex, std::call_once, etc? lld has been using all of these things for some time now, and in theory we have the same baseline toolchain requirements.
If it’s just std::recursive_mutex, how long do you think it would take to implement that for mingw’s libstdc++?
Do you have a sense of which version of mingw is more popular, the pthreads variant or the win32 threads variant? If the overwhelming majority use the win32 threads variant, I don’t think we can break it.
On Windows, MinGW is the gcc distribution so a)==b). The stackoverflow link above is for 4.7.2 but it’s also correct for 4.8.2 and the latest 4.9: _GLIBCXX_HAS_GTHREADS is not defined in c++config.h in the wIndows threads dist. so “mutex” does not provide recursive_mutex and mutex.
It’s odd since the win32 dist. is shipped with libwinpthread-1.dll so defining _GLIBCXX_HAS_GTHREADS may actually work.
The whole “mutex” and “shared_mutex” files are #ifdef _GLIBCXX_HAS_GTHREADS so if no _GLIBCXX_HAS_GTHREADS there are no mutexes and no call_once. thread lives in “thread” which is also #ifdef _GLIBCXX_HAS_GTHREADS.
“condition_variable” and “future” are the same.
I have tested gcc 4.8.2 predefines and _GLIBCXX_HAS_GTHREADS isn’t there nor it is defined anywhere with the win32 version. I have also compiled a small test and indeed it failed with
a.cpp:4:3: error: ‘mutex’ is not a member of ‘std’.
Just for fun, I tried to compile it with -D_GLIBCXX_HAS_GTHREADS but then it failed on bunch of other errors starting with
error: ‘__gthread_time_t’ was not declared in this scope
so gthreads isn’t there.
As to popularity, compare the download graphs for 32 bit:
Another thought is that we could introduce a configuration for
threading and just conditionalize all of the uses on that and turn it
off by default for mingw. If a target doesn’t support threading it
doesn’t support it?
Revert and give up on C++11 threading libraries for now.
Do what Eric suggests. Move all the mutex usage under #ifdef LLVM_ENABLE_THREADS, and disable LLVM_ENABLE_THREADS by default on MinGW. MinGW plus LLVM_ENABLE_THREADS would become unsupported.
Do people have objections to 2? I don’t really like it either.
#2 is better if we can detect threads-win32 vs threads-posix on MinGW, and only disable this for threads-posix. We can check for _GLIBCXX_HAS_GTHREADS, but that seems somewhat hackish, so I wonder if there’s a better way.
To handle the switching, I guess we’ll have to go back to the original option of having llvm::mutex, llvm::recursive_mutex, etc, and then conditionally typedefing them. Kinda sucks, but still better than getting rid of it entirely.
I suppose there’s also an option #3: “declare that LLVM only supports the threads-posix flavor”. As long as configure script gives a clear error message…
Hmm, that’s no good either. Someone pointed out to me that the reason for implementing this as a semaphore probably has to do with the fact that std::mutex can be used with a std::condition_variable, and you can’t make that work with a critical section. Still, there are better ways to implement it, because on Vista+ Windows provides a native condition variable object. Still though, it’s unfortunate.
I’m not really sure what the right solution is. I’ll let this thread bake for a little while and get some more comments, but I may end up reverting this patch if there’s no good solution.
We are already seeing an increasing interest in using LLVM in multithreaded
contexts at least, and I have a concrete need to add multithreaded support
to LLVM. It would be really, really terrible to be unable to use extremely
basic and standardized primitives for this such as std::mutex and
std::call_once.
I don't really care that MinGW's mutexes would be slow. The current usage
patterns of LLVM don't put them in the critical path, and in the future it
seems like there has to be a non-terrible way of implementing MinGW's
standard library without such sorrow. And ultimately, this is just a MinGW
bug. It is hardly the only one that makes this platform somewhat suboptimal.
The standard library std::mutex and std::call_once implementations are
going to get better and more widely available. It seems a mistake to
continually burden ourselves with coping with bad instances.