Pipette and "On Preview Widgets" branch. See issue 227
The pipette part is already working quite nice but need to be finished. The widgets part needs more work...
This commit is contained in:
619
rtgui/threadutils.h
Normal file
619
rtgui/threadutils.h
Normal file
@@ -0,0 +1,619 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||
*
|
||||
* RawTherapee is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RawTherapee is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _THREADUTILS_
|
||||
#define _THREADUTILS_
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <csignal> // for raise()
|
||||
#include <iostream>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NDEBUG
|
||||
// We don't trace mutex
|
||||
#undef TRACE_MYRWMUTEX
|
||||
#define TRACE_MYRWMUTEX 0
|
||||
#endif
|
||||
|
||||
|
||||
// Uncomment this if you want to bypass the CMakeList options and force the values
|
||||
// Of course, DO NOT COMMIT!
|
||||
|
||||
//#undef PROTECT_VECTORS
|
||||
//#define PROTECT_VECTORS 1
|
||||
//#undef TRACE_MYRWMUTEX
|
||||
//#define TRACE_MYRWMUTEX 1
|
||||
//#undef STRICT_MUTEX
|
||||
//#define STRICT_MUTEX 1
|
||||
|
||||
/**
|
||||
* @brief Custom Mutex to replace Glib::Threads::Mutex, which behave differently on windows (recursive) and linux (non-recursive), by a recursive and "debugable" one
|
||||
*
|
||||
* This implementation will behave like a Glib::Threads::RecMutex (STRICT_MUTEX=0) or a Glib::Threads::Mutex (STRICT_MUTEX=1), but in this case, the application will
|
||||
* crash instead of freezing.
|
||||
*
|
||||
* In Debug builds, a printf will let you know that the MyMutex was already locked
|
||||
*
|
||||
* The default and recommended mode is STRICT_MUTEX=1
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
class MyMutex : public Glib::RecMutex {
|
||||
#else
|
||||
class MyMutex : public Glib::Threads::RecMutex {
|
||||
#endif
|
||||
|
||||
#if STRICT_MUTEX || !defined(NDEBUG)
|
||||
private:
|
||||
bool alreadyLocked;
|
||||
#endif
|
||||
|
||||
public:
|
||||
class MyLock;
|
||||
|
||||
#if STRICT_MUTEX || !defined(NDEBUG)
|
||||
MyMutex() : alreadyLocked(false) {}
|
||||
#else
|
||||
MyMutex() {}
|
||||
#endif
|
||||
|
||||
void lock() {
|
||||
#ifdef WIN32
|
||||
Glib::RecMutex::lock();
|
||||
#else
|
||||
Glib::Threads::RecMutex::lock();
|
||||
#endif
|
||||
#if STRICT_MUTEX || !defined(NDEBUG)
|
||||
if (alreadyLocked) {
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Warning: MyMutex already locked!" << std::endl; // breakpoint
|
||||
#endif
|
||||
#if STRICT_MUTEX
|
||||
#ifndef NDEBUG
|
||||
#ifdef WIN32
|
||||
DebugBreak();
|
||||
#else
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
#else
|
||||
raise(SIGINT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
alreadyLocked = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool trylock() {
|
||||
#ifdef WIN32
|
||||
if (Glib::RecMutex::trylock())
|
||||
#else
|
||||
if (Glib::Threads::RecMutex::trylock())
|
||||
#endif
|
||||
{
|
||||
#if STRICT_MUTEX || !defined(NDEBUG)
|
||||
if (alreadyLocked) {
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Warning: MyMutex already locked!" << std::endl; // breakpoint
|
||||
#endif
|
||||
#if STRICT_MUTEX
|
||||
#ifndef NDEBUG
|
||||
#ifdef WIN32
|
||||
DebugBreak();
|
||||
#else
|
||||
raise(SIGTRAP);
|
||||
#endif
|
||||
#else
|
||||
raise(SIGINT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
alreadyLocked = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Warning: the base class of MyMutex is RecMutex, but the mutex is said "unlocked" on first occurrence of "unlock", to avoid overhead.
|
||||
void unlock() {
|
||||
#if STRICT_MUTEX || !defined(NDEBUG)
|
||||
alreadyLocked = false;
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
Glib::RecMutex::unlock();
|
||||
#else
|
||||
Glib::Threads::RecMutex::unlock();
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Class copied from the Glibmm source code, to provide a workaround of the behavior's difference between Linux and Windows
|
||||
class MyMutex::MyLock {
|
||||
public:
|
||||
explicit inline MyLock(MyMutex& mutex) : mutex_ (mutex), locked_ (true) { mutex_.lock(); }
|
||||
#ifdef WIN32
|
||||
inline MyLock(MyMutex& mutex, Glib::NotLock) : mutex_ (mutex), locked_ (false) {}
|
||||
inline MyLock(MyMutex& mutex, Glib::TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {}
|
||||
#else
|
||||
inline MyLock(MyMutex& mutex, Glib::Threads::NotLock) : mutex_ (mutex), locked_ (false) {}
|
||||
inline MyLock(MyMutex& mutex, Glib::Threads::TryLock) : mutex_ (mutex), locked_ (mutex.trylock()) {}
|
||||
#endif
|
||||
inline ~MyLock() { if(locked_) mutex_.unlock(); }
|
||||
|
||||
inline void acquire() { mutex_.lock(); locked_ = true; }
|
||||
inline bool try_acquire() { locked_ = mutex_.trylock(); return locked_; }
|
||||
inline void release() { mutex_.unlock(); locked_ = false; }
|
||||
inline bool locked() const { return locked_; }
|
||||
|
||||
private:
|
||||
MyMutex& mutex_;
|
||||
bool locked_;
|
||||
|
||||
// noncopyable
|
||||
MyLock(const MyMutex::Lock&);
|
||||
MyMutex::Lock& operator=(const MyMutex::Lock&);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Custom RWLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
* It may be slower, but thread safe!
|
||||
*/
|
||||
class MyRWMutex {
|
||||
public:
|
||||
#ifdef WIN32
|
||||
Glib::Mutex handlerMutex; // Having a recursive or non-recursive mutex is not important here, so we can use Glib::Mutex
|
||||
Glib::Cond access;
|
||||
#else
|
||||
Glib::Threads::Mutex handlerMutex; // Having a recursive or non-recursive mutex is not important here, so we can use Glib::Threads::Mutex
|
||||
Glib::Threads::Cond access;
|
||||
#endif
|
||||
size_t writerCount;
|
||||
size_t readerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
Glib::ustring lastWriterFile;
|
||||
int lastWriterLine;
|
||||
// Unfortunately, ownerThread may not be the culprit of a deadlock, it can be another concurrent Reader...
|
||||
void* ownerThread;
|
||||
|
||||
MyRWMutex() : writerCount(0), readerCount(0), lastWriterLine(0), ownerThread(NULL) {}
|
||||
#else
|
||||
MyRWMutex() : writerCount(0), readerCount(0) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom ReaderLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
*/
|
||||
class MyReaderLock {
|
||||
|
||||
MyRWMutex& rwMutex;
|
||||
bool locked;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
static unsigned int readerLockCounter;
|
||||
int locknumber;
|
||||
|
||||
public:
|
||||
inline MyReaderLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
|
||||
#else
|
||||
public:
|
||||
inline MyReaderLock(MyRWMutex& mutex) : rwMutex(mutex)
|
||||
#endif
|
||||
|
||||
{
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
locknumber = readerLockCounter++;
|
||||
void* thread = Glib::Thread::self();
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
// There's no writer operating, we can increment the writer count which will lock writers
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " ++ new owner";
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// The writer count is non null, but we can be the owner of the writer lock
|
||||
// It will be the case if the reader count is non null too.
|
||||
if (!rwMutex.readerCount) {
|
||||
// the mutex is in real write mode, we're waiting to see it null
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - R ++ new owner";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire(const char* file, const int line)
|
||||
#else
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (!locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock)";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
// There's no writer operating, we can increment the writer count which will lock writers
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " ++ new owner";
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// The writer count is non null, but a reader can be the owner of the writer lock,
|
||||
// it will be the case if the reader count is non null too.
|
||||
if (!rwMutex.readerCount) {
|
||||
// the mutex is in real write mode, we're waiting to see it null
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
++rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - R (lock) ++ new owner";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " - ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already locked by this object - R (lock)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
inline ~MyReaderLock() {
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - R - ReaderCount: " << rwMutex.readerCount;
|
||||
#endif
|
||||
|
||||
if (!rwMutex.readerCount) {
|
||||
// no more reader, so we decrement the writer count
|
||||
--rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
|
||||
#endif
|
||||
// and signal the next waiting reader/writer that it's free
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - R" << std::endl;
|
||||
#endif
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release(const char* file, const int line)
|
||||
#else
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.readerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - R (release) - ReaderCount: " << rwMutex.readerCount;
|
||||
#endif
|
||||
|
||||
if (!rwMutex.readerCount) {
|
||||
// no more reader, so we decrement the writer count
|
||||
--rwMutex.writerCount;
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!" << " >>> ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount;
|
||||
#endif
|
||||
// and signal the next waiting reader/writer that it's free
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = false;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked - R (release)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Custom WriterLock with debugging feature, to replace the buggy Glib::RWLock (can have negative reader_count value!)
|
||||
*
|
||||
*/
|
||||
class MyWriterLock {
|
||||
|
||||
MyRWMutex& rwMutex;
|
||||
bool locked;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
static unsigned int writerLockCounter;
|
||||
int locknumber;
|
||||
public:
|
||||
inline MyWriterLock(MyRWMutex& mutex, const char* name, const char* file, const int line) : rwMutex(mutex), locked(false), locknumber(0)
|
||||
#else
|
||||
public:
|
||||
inline MyWriterLock(MyRWMutex& mutex) : rwMutex(mutex)
|
||||
#endif
|
||||
{
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
locknumber = writerLockCounter++;
|
||||
void* thread = Glib::Thread::self();
|
||||
std::cout << thread << "/" << locknumber << ":" << name << " / " << file << " : " << line << " - locking - W";
|
||||
#endif
|
||||
|
||||
if (rwMutex.writerCount) {
|
||||
// The writer count is non null, so we have to wait for it to be null again
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W";
|
||||
#endif
|
||||
}
|
||||
// then we can increment the writer count
|
||||
++rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire(const char* file, const int line)
|
||||
#else
|
||||
// locks the MyRWMutex with Read access if this MyReaderLock has not already locked it, otherwise return safely
|
||||
inline void acquire()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (!locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
|
||||
#endif
|
||||
|
||||
if (rwMutex.writerCount) {
|
||||
// The writer count is non null, so we have to wait for it to be null again
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " waiting..." << std::endl << "Current writer owner: " << rwMutex.lastWriterFile << " : " << rwMutex.lastWriterLine << std::endl;
|
||||
#endif
|
||||
while (rwMutex.writerCount)
|
||||
rwMutex.access.wait(rwMutex.handlerMutex);
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << ":" << file << " : " << line << " - locking - W (lock)";
|
||||
#endif
|
||||
}
|
||||
// then we can increment the reader count
|
||||
++rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = file;
|
||||
rwMutex.lastWriterLine = line;
|
||||
rwMutex.ownerThread = thread;
|
||||
std::cout << " ++ new owner <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already locked by this object - W (lock)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
inline ~MyWriterLock() {
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - W";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!";
|
||||
#endif
|
||||
// The writer count is null again, so we can wake up the next writer or reader
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W" << std::endl;
|
||||
#endif
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release(const char* file, const int line)
|
||||
#else
|
||||
// releases the MyRWMutex with Write access if this MyWriterLock has already locked it, otherwise return safely
|
||||
inline void release()
|
||||
#endif
|
||||
{
|
||||
#if TRACE_MYRWMUTEX
|
||||
void* thread = Glib::Thread::self();
|
||||
#endif
|
||||
if (locked) {
|
||||
// to operate safely
|
||||
rwMutex.handlerMutex.lock();
|
||||
|
||||
// decrement the writer number first
|
||||
--rwMutex.writerCount;
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << thread << "/" << locknumber << " / unlocking - W (release)";
|
||||
#endif
|
||||
|
||||
if (!rwMutex.writerCount) {
|
||||
#if TRACE_MYRWMUTEX
|
||||
rwMutex.lastWriterFile = "";
|
||||
rwMutex.lastWriterLine = 0;
|
||||
rwMutex.ownerThread = NULL;
|
||||
std::cout << " -- new owner possible!";
|
||||
#endif
|
||||
// The writer count is null again, so we can wake up the next writer or reader
|
||||
rwMutex.access.broadcast();
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
std::cout << " <<< ReaderCount: " << rwMutex.readerCount << " - WriterCount: " << rwMutex.writerCount << std::endl;
|
||||
#endif
|
||||
|
||||
rwMutex.handlerMutex.unlock();
|
||||
|
||||
locked = false;
|
||||
}
|
||||
#if TRACE_MYRWMUTEX
|
||||
else std::cout << thread << "/" << locknumber << " / already unlocked by this object - W (release)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if TRACE_MYRWMUTEX
|
||||
#define MYREADERLOCK(ln, e) MyReaderLock ln(e, #e, __FILE__, __LINE__);
|
||||
#define MYWRITERLOCK(ln, e) MyWriterLock ln(e, #e, __FILE__, __LINE__);
|
||||
#define MYREADERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
|
||||
#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire(__FILE__, __LINE__);
|
||||
#define MYREADERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__);
|
||||
#define MYWRITERLOCK_RELEASE(ln) ln.release(__FILE__, __LINE__);
|
||||
#else
|
||||
#define MYREADERLOCK(ln, e) MyReaderLock ln(e);
|
||||
#define MYWRITERLOCK(ln, e) MyWriterLock ln(e);
|
||||
#define MYREADERLOCK_ACQUIRE(ln) ln.acquire();
|
||||
#define MYWRITERLOCK_ACQUIRE(ln) ln.acquire();
|
||||
#define MYREADERLOCK_RELEASE(ln) ln.release();
|
||||
#define MYWRITERLOCK_RELEASE(ln) ln.release();
|
||||
#endif
|
||||
|
||||
#endif /* _THREADUTILS_ */
|
Reference in New Issue
Block a user