diff --git a/include/znc/Threads.h b/include/znc/Threads.h index 8590bb25..1bd3a53a 100644 --- a/include/znc/Threads.h +++ b/include/znc/Threads.h @@ -29,179 +29,27 @@ #include #include #include +#include +#include /** * This class represents a non-recursive mutex. Only a single thread may own the * mutex at any point in time. */ -class CMutex { -public: - friend class CConditionVariable; - - CMutex() : m_mutex() { - int i = pthread_mutex_init(&m_mutex, nullptr); - if (i) { - CUtils::PrintError("Can't initialize mutex: " + CString(strerror(errno))); - exit(1); - } - } - - ~CMutex() { - int i = pthread_mutex_destroy(&m_mutex); - if (i) { - CUtils::PrintError("Can't destroy mutex: " + CString(strerror(errno))); - exit(1); - } - } - - void lock() { - int i = pthread_mutex_lock(&m_mutex); - if (i) { - CUtils::PrintError("Can't lock mutex: " + CString(strerror(errno))); - exit(1); - } - } - - void unlock() { - int i = pthread_mutex_unlock(&m_mutex); - if (i) { - CUtils::PrintError("Can't unlock mutex: " + CString(strerror(errno))); - exit(1); - } - } - -private: - // Undefined copy constructor and assignment operator - CMutex(const CMutex&); - CMutex& operator=(const CMutex&); - - pthread_mutex_t m_mutex; -}; +using CMutex = std::mutex; /** * A mutex locker should always be used as an automatic variable. This * class makes sure that the mutex is unlocked when this class is destructed. * For example, this makes it easier to make code exception-safe. */ -class CMutexLocker { -public: - CMutexLocker(CMutex& mutex, bool initiallyLocked = true) - : m_mutex(mutex), m_locked(false) { - if (initiallyLocked) - lock(); - } - - ~CMutexLocker() { - if (m_locked) - unlock(); - } - - void lock() { - assert(!m_locked); - m_mutex.lock(); - m_locked = true; - } - - void unlock() { - assert(m_locked); - m_locked = false; - m_mutex.unlock(); - } - -private: - // Undefined copy constructor and assignment operator - CMutexLocker(const CMutexLocker&); - CMutexLocker& operator=(const CMutexLocker&); - - CMutex &m_mutex; - bool m_locked; -}; +using CMutexLocker = std::unique_lock; /** * A condition variable makes it possible for threads to wait until some * condition is reached at which point the thread can wake up again. */ -class CConditionVariable { -public: - CConditionVariable() : m_cond() { - int i = pthread_cond_init(&m_cond, nullptr); - if (i) { - CUtils::PrintError("Can't initialize condition variable: " - + CString(strerror(errno))); - exit(1); - } - } - - ~CConditionVariable() { - int i = pthread_cond_destroy(&m_cond); - if (i) { - CUtils::PrintError("Can't destroy condition variable: " - + CString(strerror(errno))); - exit(1); - } - } - - void wait(CMutex& mutex) { - int i = pthread_cond_wait(&m_cond, &mutex.m_mutex); - if (i) { - CUtils::PrintError("Can't wait on condition variable: " - + CString(strerror(errno))); - exit(1); - } - } - - void signal() { - int i = pthread_cond_signal(&m_cond); - if (i) { - CUtils::PrintError("Can't signal condition variable: " - + CString(strerror(errno))); - exit(1); - } - } - - void broadcast() { - int i = pthread_cond_broadcast(&m_cond); - if (i) { - CUtils::PrintError("Can't broadcast condition variable: " - + CString(strerror(errno))); - exit(1); - } - } - -private: - // Undefined copy constructor and assignment operator - CConditionVariable(const CConditionVariable&); - CConditionVariable& operator=(const CConditionVariable&); - - pthread_cond_t m_cond; -}; - -class CThread { -public: - typedef void *threadRoutine(void *); - static void startThread(threadRoutine *func, void *arg) { - pthread_t thr; - sigset_t old_sigmask, sigmask; - - /* Block all signals. The thread will inherit our signal mask - * and thus won't ever try to handle signals. - */ - int i = sigfillset(&sigmask); - i |= pthread_sigmask(SIG_SETMASK, &sigmask, &old_sigmask); - i |= pthread_create(&thr, nullptr, func, arg); - i |= pthread_sigmask(SIG_SETMASK, &old_sigmask, nullptr); - i |= pthread_detach(thr); - if (i) { - CUtils::PrintError("Can't start new thread: " - + CString(strerror(errno))); - exit(1); - } - } - -private: - // Undefined constructor - CThread(); -}; +using CConditionVariable = std::condition_variable_any; /** * A job is a task which should run without blocking the main thread. You do @@ -292,11 +140,6 @@ private: void finishJob(CJob *) const; void threadFunc(); - static void *threadPoolFunc(void *arg) { - CThreadPool &pool = *reinterpret_cast(arg); - pool.threadFunc(); - return nullptr; - } // mutex protecting all of these members CMutex m_mutex; diff --git a/src/Threads.cpp b/src/Threads.cpp index 9197d620..1f15f518 100644 --- a/src/Threads.cpp +++ b/src/Threads.cpp @@ -20,6 +20,7 @@ #include #include +#include /* Just an arbitrary limit for the number of idle threads */ static const size_t MAX_IDLE_THREADS = 3; @@ -49,7 +50,7 @@ void CThreadPool::jobDone(CJob* job) { if (oldState == CJob::CANCELLED) { // Signal the main thread that cancellation is done - m_cancellationCond.signal(); + m_cancellationCond.notify_one(); return; } @@ -88,7 +89,7 @@ CThreadPool::~CThreadPool() { m_done = true; while (m_num_threads > 0) { - m_cond.broadcast(); + m_cond.notify_all(); m_exit_cond.wait(m_mutex); } } @@ -133,7 +134,7 @@ void CThreadPool::threadFunc() { m_num_idle--; if (m_num_threads == 0 && m_done) - m_exit_cond.signal(); + m_exit_cond.notify_one(); } void CThreadPool::addJob(CJob *job) { @@ -142,7 +143,7 @@ void CThreadPool::addJob(CJob *job) { // Do we already have a thread which can handle this job? if (m_num_idle > 0) { - m_cond.signal(); + m_cond.notify_one(); return; } @@ -153,7 +154,9 @@ void CThreadPool::addJob(CJob *job) { // Start a new thread for our pool m_num_threads++; - CThread::startThread(threadPoolFunc, this); + std::thread([this]() { + threadFunc(); + }).detach(); } void CThreadPool::cancelJob(CJob *job) { diff --git a/test/ThreadTest.cpp b/test/ThreadTest.cpp index ad9df86c..8f06b14f 100644 --- a/test/ThreadTest.cpp +++ b/test/ThreadTest.cpp @@ -40,14 +40,14 @@ public: // and signal it to exit m_bThreadDone = true; - m_CV.broadcast(); + m_CV.notify_all(); } virtual void runThread() { CMutexLocker locker(m_Mutex); // We are running m_bThreadReady = true; - m_CV.broadcast(); + m_CV.notify_all(); // wait for our exit signal while (!m_bThreadDone) @@ -97,7 +97,7 @@ public: m_Mutex.lock(); // We are running, tell the main thread m_bThreadReady = true; - m_CVThreadReady.broadcast(); + m_CVThreadReady.notify_all(); // Have to unlock here so that wait() can get the mutex m_Mutex.unlock();