Fix C++11 Windows build of threading code

The initial problem was that mutex_auto_lock.h tries to use std::unique_lock<std::mutex>
	despite mutex.h not using C++11's std::mutex on Windows. The problem here is the mismatch
	between C++11 usage conditions of the two headers. This commit moves the decision logic
	to threads.h and makes sure mutex.h, mutex_auto_lock.h and event.h all use the same features.
This commit is contained in:
sfan5 2016-10-06 21:13:04 +02:00
parent 155288ee98
commit 0a16e53b40
8 changed files with 65 additions and 57 deletions

View File

@ -27,8 +27,8 @@ DEALINGS IN THE SOFTWARE.
Event::Event() Event::Event()
{ {
#if __cplusplus < 201103L #ifndef USE_CPP11_MUTEX
# ifdef _WIN32 # if USE_WIN_MUTEX
event = CreateEvent(NULL, false, false, NULL); event = CreateEvent(NULL, false, false, NULL);
# else # else
pthread_cond_init(&cv, NULL); pthread_cond_init(&cv, NULL);
@ -38,10 +38,10 @@ Event::Event()
#endif #endif
} }
#if __cplusplus < 201103L #ifndef USE_CPP11_MUTEX
Event::~Event() Event::~Event()
{ {
#ifdef _WIN32 #if USE_WIN_MUTEX
CloseHandle(event); CloseHandle(event);
#else #else
pthread_cond_destroy(&cv); pthread_cond_destroy(&cv);
@ -53,13 +53,13 @@ Event::~Event()
void Event::wait() void Event::wait()
{ {
#if __cplusplus >= 201103L #if USE_CPP11_MUTEX
MutexAutoLock lock(mutex); MutexAutoLock lock(mutex);
while (!notified) { while (!notified) {
cv.wait(lock); cv.wait(lock);
} }
notified = false; notified = false;
#elif defined(_WIN32) #elif USE_WIN_MUTEX
WaitForSingleObject(event, INFINITE); WaitForSingleObject(event, INFINITE);
#else #else
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
@ -74,11 +74,11 @@ void Event::wait()
void Event::signal() void Event::signal()
{ {
#if __cplusplus >= 201103L #if USE_CPP11_MUTEX
MutexAutoLock lock(mutex); MutexAutoLock lock(mutex);
notified = true; notified = true;
cv.notify_one(); cv.notify_one();
#elif defined(_WIN32) #elif USE_WIN_MUTEX
SetEvent(event); SetEvent(event);
#else #else
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);

View File

@ -26,17 +26,12 @@ DEALINGS IN THE SOFTWARE.
#ifndef THREADING_EVENT_H #ifndef THREADING_EVENT_H
#define THREADING_EVENT_H #define THREADING_EVENT_H
#if __cplusplus >= 201103L #include "threads.h"
#if USE_CPP11_MUTEX
#include <condition_variable> #include <condition_variable>
#include "threading/mutex.h" #include "threading/mutex.h"
#include "threading/mutex_auto_lock.h" #include "threading/mutex_auto_lock.h"
#elif defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#else
#include <pthread.h>
#endif #endif
@ -49,18 +44,18 @@ DEALINGS IN THE SOFTWARE.
class Event { class Event {
public: public:
Event(); Event();
#if __cplusplus < 201103L #ifndef USE_CPP11_MUTEX
~Event(); ~Event();
#endif #endif
void wait(); void wait();
void signal(); void signal();
private: private:
#if __cplusplus >= 201103L #if USE_CPP11_MUTEX
std::condition_variable cv; std::condition_variable cv;
Mutex mutex; Mutex mutex;
bool notified; bool notified;
#elif defined(_WIN32) #elif USE_WIN_MUTEX
HANDLE event; HANDLE event;
#else #else
pthread_cond_t cv; pthread_cond_t cv;

View File

@ -23,14 +23,13 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
// Windows std::mutex is much slower than the critical section API #include "threads.h"
#if __cplusplus < 201103L || defined(_WIN32)
#ifndef USE_CPP11_MUTEX
#include "threading/mutex.h" #include "threading/mutex.h"
#ifndef _WIN32 #include <cassert>
#include <cassert>
#endif
#define UNUSED(expr) do { (void)(expr); } while (0) #define UNUSED(expr) do { (void)(expr); } while (0)
@ -47,7 +46,7 @@ Mutex::Mutex(bool recursive)
void Mutex::init_mutex(bool recursive) void Mutex::init_mutex(bool recursive)
{ {
#ifdef _WIN32 #if USE_WIN_MUTEX
// Windows critical sections are recursive by default // Windows critical sections are recursive by default
UNUSED(recursive); UNUSED(recursive);
@ -69,7 +68,7 @@ void Mutex::init_mutex(bool recursive)
Mutex::~Mutex() Mutex::~Mutex()
{ {
#ifdef _WIN32 #if USE_WIN_MUTEX
DeleteCriticalSection(&mutex); DeleteCriticalSection(&mutex);
#else #else
int ret = pthread_mutex_destroy(&mutex); int ret = pthread_mutex_destroy(&mutex);
@ -80,7 +79,7 @@ Mutex::~Mutex()
void Mutex::lock() void Mutex::lock()
{ {
#ifdef _WIN32 #if USE_WIN_MUTEX
EnterCriticalSection(&mutex); EnterCriticalSection(&mutex);
#else #else
int ret = pthread_mutex_lock(&mutex); int ret = pthread_mutex_lock(&mutex);
@ -91,7 +90,7 @@ void Mutex::lock()
void Mutex::unlock() void Mutex::unlock()
{ {
#ifdef _WIN32 #if USE_WIN_MUTEX
LeaveCriticalSection(&mutex); LeaveCriticalSection(&mutex);
#else #else
int ret = pthread_mutex_unlock(&mutex); int ret = pthread_mutex_unlock(&mutex);
@ -104,5 +103,5 @@ RecursiveMutex::RecursiveMutex()
: Mutex(true) : Mutex(true)
{} {}
#endif #endif // C++11

View File

@ -26,14 +26,15 @@ DEALINGS IN THE SOFTWARE.
#ifndef THREADING_MUTEX_H #ifndef THREADING_MUTEX_H
#define THREADING_MUTEX_H #define THREADING_MUTEX_H
// Windows std::mutex is much slower than the critical section API #include "threads.h"
#if __cplusplus >= 201103L && !defined(_WIN32)
#if USE_CPP11_MUTEX
#include <mutex> #include <mutex>
using Mutex = std::mutex; using Mutex = std::mutex;
using RecursiveMutex = std::recursive_mutex; using RecursiveMutex = std::recursive_mutex;
#else #else
#ifdef _WIN32 #if USE_WIN_MUTEX
#ifndef _WIN32_WINNT #ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501 #define _WIN32_WINNT 0x0501
#endif #endif
@ -41,7 +42,7 @@ DEALINGS IN THE SOFTWARE.
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#endif #endif
#include <windows.h> #include <windows.h>
#else // pthread #else
#include <pthread.h> #include <pthread.h>
#endif #endif
@ -59,9 +60,9 @@ protected:
Mutex(bool recursive); Mutex(bool recursive);
void init_mutex(bool recursive); void init_mutex(bool recursive);
private: private:
#ifdef _WIN32 #if USE_WIN_MUTEX
CRITICAL_SECTION mutex; CRITICAL_SECTION mutex;
#else // pthread #else
pthread_mutex_t mutex; pthread_mutex_t mutex;
#endif #endif
@ -76,6 +77,6 @@ public:
DISABLE_CLASS_COPY(RecursiveMutex); DISABLE_CLASS_COPY(RecursiveMutex);
}; };
#endif // C++11 #endif // C++11
#endif #endif

View File

@ -26,7 +26,9 @@ DEALINGS IN THE SOFTWARE.
#ifndef THREADING_MUTEX_AUTO_LOCK_H #ifndef THREADING_MUTEX_AUTO_LOCK_H
#define THREADING_MUTEX_AUTO_LOCK_H #define THREADING_MUTEX_AUTO_LOCK_H
#if __cplusplus >= 201103L #include "threads.h"
#if USE_CPP11_MUTEX
#include <mutex> #include <mutex>
using MutexAutoLock = std::unique_lock<std::mutex>; using MutexAutoLock = std::unique_lock<std::mutex>;
using RecursiveMutexAutoLock = std::unique_lock<std::recursive_mutex>; using RecursiveMutexAutoLock = std::unique_lock<std::recursive_mutex>;

View File

@ -198,7 +198,7 @@ bool Thread::kill()
m_running = false; m_running = false;
#ifdef _WIN32 #if USE_WIN_THREADS
TerminateThread(m_thread_handle, 0); TerminateThread(m_thread_handle, 0);
CloseHandle(m_thread_handle); CloseHandle(m_thread_handle);
#else #else
@ -310,10 +310,16 @@ void Thread::setName(const std::string &name)
unsigned int Thread::getNumberOfProcessors() unsigned int Thread::getNumberOfProcessors()
{ {
#if __cplusplus >= 201103L #if USE_CPP11_THREADS
return std::thread::hardware_concurrency(); return std::thread::hardware_concurrency();
#elif USE_WIN_THREADS
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif defined(_SC_NPROCESSORS_ONLN) #elif defined(_SC_NPROCESSORS_ONLN)
return sysconf(_SC_NPROCESSORS_ONLN); return sysconf(_SC_NPROCESSORS_ONLN);
@ -335,12 +341,6 @@ unsigned int Thread::getNumberOfProcessors()
return get_nprocs(); return get_nprocs();
#elif defined(_WIN32)
SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
return sysinfo.dwNumberOfProcessors;
#elif defined(PTW32_VERSION) || defined(__hpux) #elif defined(PTW32_VERSION) || defined(__hpux)
return pthread_num_processors_np(); return pthread_num_processors_np();
@ -359,7 +359,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
return false; return false;
#elif defined(_WIN32) #elif USE_WIN_THREADS
return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number); return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
@ -407,7 +407,7 @@ bool Thread::bindToProcessor(unsigned int proc_number)
bool Thread::setPriority(int prio) bool Thread::setPriority(int prio)
{ {
#if defined(_WIN32) #if USE_WIN_THREADS
return SetThreadPriority(getThreadHandle(), prio); return SetThreadPriority(getThreadHandle(), prio);

View File

@ -32,9 +32,6 @@ DEALINGS IN THE SOFTWARE.
#include "threads.h" #include "threads.h"
#include <string> #include <string>
#if USE_CPP11_THREADS
#include <thread> // for std::thread
#endif
#ifdef _AIX #ifdef _AIX
#include <sys/thread.h> // for tid_t #include <sys/thread.h> // for tid_t
#endif #endif
@ -157,9 +154,11 @@ private:
Atomic<bool> m_running; Atomic<bool> m_running;
Mutex m_mutex; Mutex m_mutex;
#ifndef USE_CPP11_THREADS #if USE_CPP11_THREADS
std::thread *m_thread_obj;
#else
threadhandle_t m_thread_handle; threadhandle_t m_thread_handle;
# if _WIN32 # if USE_WIN_THREADS
threadid_t m_thread_id; threadid_t m_thread_id;
# endif # endif
#endif #endif
@ -172,10 +171,6 @@ private:
tid_t m_kernel_thread_id; tid_t m_kernel_thread_id;
#endif #endif
#if USE_CPP11_THREADS
std::thread *m_thread_obj;
#endif
DISABLE_CLASS_COPY(Thread); DISABLE_CLASS_COPY(Thread);
}; };

View File

@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define THREADS_HEADER #define THREADS_HEADER
// //
// Determine which threading API we will use // Determine which threading APIs we will use
// //
#if __cplusplus >= 201103L #if __cplusplus >= 201103L
#define USE_CPP11_THREADS 1 #define USE_CPP11_THREADS 1
@ -31,11 +31,27 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define USE_POSIX_THREADS 1 #define USE_POSIX_THREADS 1
#endif #endif
#if defined(_WIN32)
// Prefer critical section API because std::mutex is much slower on Windows
#define USE_WIN_MUTEX 1
#elif __cplusplus >= 201103L
#define USE_CPP11_MUTEX 1
#else
#define USE_POSIX_MUTEX 1
#endif
/////////////// ///////////////
#if USE_CPP11_THREADS #if USE_CPP11_THREADS
#include <thread> #include <thread>
#elif USE_POSIX_THREADS
#include <pthread.h>
#else
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#endif #endif
#include "threading/mutex.h" #include "threading/mutex.h"