diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 821f6f0be..b804218f5 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1197,7 +1197,7 @@ void HistogramArea::update( break; case ScopeType::PARADE: case ScopeType::WAVEFORM: { - MyWriterLock wave_lock(wave_mutex); + MYWRITERLOCK(wave_lock, wave_mutex) waveform_scale = waveformScale; rwave = waveformRed; gwave = waveformGreen; @@ -1330,7 +1330,7 @@ void HistogramArea::updateBackBuffer () cr->unset_dash(); - MyReaderLock wave_lock(wave_mutex); + MYREADERLOCK(wave_lock, wave_mutex) if (valid && (scopeType == ScopeType::HISTOGRAM || scopeType == ScopeType::HISTOGRAM_RAW)) { bool rawMode = scopeType == ScopeType::HISTOGRAM_RAW; @@ -1447,7 +1447,7 @@ void HistogramArea::updateBackBuffer () } else if (scopeType == ScopeType::VECTORSCOPE_HC || scopeType == ScopeType::VECTORSCOPE_HS) { drawVectorscope(cr, w, h); } - wave_lock.release(); + MYREADERLOCK_RELEASE(wave_lock); // Draw the frame's border style->render_frame(cr, 0, 0, surface->get_width(), surface->get_height()); diff --git a/rtgui/threadutils.cc b/rtgui/threadutils.cc index f747510d3..9bc9cf35d 100644 --- a/rtgui/threadutils.cc +++ b/rtgui/threadutils.cc @@ -17,7 +17,6 @@ * along with RawTherapee. If not, see . */ #include "threadutils.h" -#include #include #include @@ -28,6 +27,8 @@ #if STRICT_MUTEX && !NDEBUG +MyMutex::MyMutex() : locked(false) {} + void MyMutex::checkLock () { if (locked) { @@ -62,13 +63,18 @@ void MyMutex::checkUnlock () #if !TRACE_MYRWMUTEX +MyRWMutex::MyRWMutex() : + writerCount(0), + readerCount(0) +{} + void MyReaderLock::acquire () { if (locked) { return; } - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); if (mutex.writerCount == 0) { // There's no writer operating, we can increment the writer count which will lock writers. @@ -77,7 +83,7 @@ void MyReaderLock::acquire () // The writer count is non null, but a reader can be the owner of the writer lock, // which will be the case if the reader count is not zero too. while (mutex.writerCount != 0) { - mutex.cond.wait(mutex.mutex); + mutex.cond.wait (lock); } // Then, we can increment the writer count. @@ -96,7 +102,7 @@ void MyReaderLock::release () return; } - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // decrement the writer number first... --mutex.readerCount; @@ -106,7 +112,7 @@ void MyReaderLock::release () --mutex.writerCount; // ...and signal the next waiting reader/writer that it's free - mutex.cond.notify_one(); // notify_all ? + mutex.cond.notify_all (); } locked = false; @@ -118,11 +124,11 @@ void MyWriterLock::acquire () return; } - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // The writer count is not zero, so we have to wait for it to be zero again... while (mutex.writerCount != 0) { - mutex.cond.wait (mutex.mutex); + mutex.cond.wait (lock); } // ...then we can increment the writer count. @@ -137,12 +143,12 @@ void MyWriterLock::release () return; } - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // Decrement the writer number first... if (--mutex.writerCount == 0) { - // ...and if the writer count is zero again, we can wake up the next writer or reader. - mutex.cond.notify_one(); // notify_all ? + // ...and if the writer count is zero again, we wake up all of the waiting writer or reader. + mutex.cond.notify_all (); } locked = false; @@ -155,13 +161,20 @@ namespace std::ostream& trace (const char* file, int line) { - const auto currentThread = Glib::Threads::Thread::self (); + const auto currentThread = std::this_thread::get_id(); return std::cout << currentThread << ":" << file << ":" << line << ": "; } } +MyRWMutex::MyRWMutex() : + lastWriterFile(nullptr), + lastWriterLine(0), + writerCount(0), + readerCount(0) +{} + void MyReaderLock::acquire (const char* file, int line) { if (locked) { @@ -171,7 +184,7 @@ void MyReaderLock::acquire (const char* file, int line) trace (file, line) << "Acquiring MyReaderLock..." << std::endl; - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); if (mutex.writerCount == 0) { // There's no writer operating, we can increment the writer count which will lock writers. @@ -185,13 +198,13 @@ void MyReaderLock::acquire (const char* file, int line) << "\tLast writer file: " << mutex.lastWriterFile << std::endl << "\tLast writer line: " << mutex.lastWriterLine << std::endl; - mutex.cond.wait(mutex.mutex); + mutex.cond.wait (lock); } // Then, we can increment the writer count. ++mutex.writerCount; - mutex.ownerThread = Glib::Threads::Thread::self (); + mutex.ownerThread = std::this_thread::get_id (); mutex.lastWriterFile = file; mutex.lastWriterLine = line; } @@ -212,7 +225,7 @@ void MyReaderLock::release (const char* file, int line) trace (file, line) << "Releasing MyReaderLock..." << std::endl; - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // decrement the writer number first... --mutex.readerCount; @@ -222,9 +235,9 @@ void MyReaderLock::release (const char* file, int line) --mutex.writerCount; // ...and signal the next waiting reader/writer that it's free - mutex.cond.notify_one(); // notify_all ? + mutex.cond.notify_all (); - mutex.ownerThread = nullptr; + mutex.ownerThread = std::thread::id(); mutex.lastWriterFile = ""; mutex.lastWriterLine = 0; } @@ -242,7 +255,7 @@ void MyWriterLock::acquire (const char* file, int line) trace (file, line) << "Acquiring MyWriterLock..." << std::endl; - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // The writer count is not zero, so we have to wait for it to be zero again... while (mutex.writerCount != 0) { @@ -251,13 +264,13 @@ void MyWriterLock::acquire (const char* file, int line) << "\tLast writer file: " << mutex.lastWriterFile << std::endl << "\tLast writer line: " << mutex.lastWriterLine << std::endl; - mutex.cond.wait (mutex.mutex); + mutex.cond.wait (lock); } // ...then we can increment the writer count. ++mutex.writerCount; - mutex.ownerThread = Glib::Threads::Thread::self (); + mutex.ownerThread = std::this_thread::get_id (); mutex.lastWriterFile = file; mutex.lastWriterLine = line; @@ -274,14 +287,14 @@ void MyWriterLock::release (const char* file, int line) trace (file, line) << "Releasing MyWriterLock..." << std::endl; - std::lock_guard lock (mutex.mutex); + std::unique_lock lock (mutex.mutex); // Decrement the writer number first... if (--mutex.writerCount == 0) { - // ...and if the writer count is zero again, we can wake up the next writer or reader. - mutex.cond.notify_one(); // notify_all ? + // ...and if the writer count is zero again, we wake up all of the waiting writer or reader. + mutex.cond.notify_all (); - mutex.ownerThread = nullptr; + mutex.ownerThread = std::thread::id(); mutex.lastWriterFile = ""; mutex.lastWriterLine = 0; } diff --git a/rtgui/threadutils.h b/rtgui/threadutils.h index cdf093b52..401660b93 100644 --- a/rtgui/threadutils.h +++ b/rtgui/threadutils.h @@ -25,6 +25,7 @@ //#define STRICT_MUTEX 1 #include +#include #include #include "../rtengine/noncopyable.h" @@ -54,8 +55,10 @@ public: void unlock (); #if STRICT_MUTEX && !NDEBUG + MyMutex(); + private: - bool locked = false; + bool locked; void checkLock (); void checkUnlock (); #endif @@ -88,18 +91,20 @@ public: friend class MyReaderLock; friend class MyWriterLock; + MyRWMutex(); + private: - std::mutex mutex; - std::condition_variable_any cond; - - std::size_t writerCount = 0; - std::size_t readerCount = 0; - #if TRACE_MYRWMUTEX - Glib::Threads::Thread* ownerThread = nullptr; - const char* lastWriterFile = ""; - int lastWriterLine = 0; + std::thread::id ownerThread; + const char* lastWriterFile; + int lastWriterLine; #endif + + std::mutex mutex; + std::condition_variable cond; + + std::size_t writerCount; + std::size_t readerCount; }; /** diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index 65958797e..d196fdca5 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -85,7 +85,7 @@ public: Glib::ThreadPool* threadPool_; - // Need to be a std::mutex because used in a std::condition_variable_any object... + // Need to be a std::mutex because used in a std::condition_variable object... // This is the only exceptions along with GThreadMutex (guiutils.cc), MyMutex is used everywhere else std::mutex mutex_; @@ -95,7 +95,7 @@ public: bool inactive_waiting_; - std::condition_variable_any inactive_; + std::condition_variable inactive_; void processNextJob() @@ -169,7 +169,7 @@ public: std::lock_guard lock(mutex_); if (inactive_waiting_) { inactive_waiting_ = false; - inactive_.notify_one(); // notify_all ? + inactive_.notify_all(); } } } @@ -246,9 +246,9 @@ void ThumbImageUpdater::removeJobs(ThumbImageUpdateListener* listener) while ( impl_->active_ != 0 ) { DEBUG("waiting for running jobs1"); { - std::lock_guard lock(impl_->mutex_); + std::unique_lock lock(impl_->mutex_); impl_->inactive_waiting_ = true; - impl_->inactive_.wait(impl_->mutex_); + impl_->inactive_.wait(lock); } } } @@ -266,9 +266,9 @@ void ThumbImageUpdater::removeAllJobs() while ( impl_->active_ != 0 ) { DEBUG("waiting for running jobs2"); { - std::lock_guard lock(impl_->mutex_); + std::unique_lock lock(impl_->mutex_); impl_->inactive_waiting_ = true; - impl_->inactive_.wait(impl_->mutex_); + impl_->inactive_.wait(lock); } } }