Skip to content

Commit

Permalink
MODIFIED: Synchronization of JKQTMathText and JKQTBasePlotter over th…
Browse files Browse the repository at this point in the history
…reads: using read/write lockers now and removed some unnecessary mutexes by using a kind of singleton pattern
  • Loading branch information
jkriege2 committed Jan 5, 2024
1 parent 11b9ac6 commit 9662ed2
Show file tree
Hide file tree
Showing 29 changed files with 1,649 additions and 1,651 deletions.
Binary file added doc/images/palettes/palette_alpha.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/palettes/palette_invalpha.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 5 additions & 2 deletions examples/multithreaded/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,13 @@ This test results in the following numbers (on my AMD Ryzen5 8/16-core laptop):

[comment]:RESULTS

<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 1822.3ms<br/>single runtimes = (227.7 +/- 306.8) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/>
<b>VERSION:</b> 5.0.0
<b>BUILD MODE:</b> Release

<u><b>SERIAL RESULTS:</b></u><br/>runtime, overall = 1896.0ms<br/>single runtimes = (236.9 +/- 379.1) ms<br/>speedup = 1.00x<br/>threads / available = 1 / 16<br/><br/>

<u><b>PARALLEL RESULTS:</b></u><br/>
runtime, overall = 811.1ms<br/>single runtimes = (760.8 +/- 63.8) ms<br/>speedup = 7.50x<br/>threads / available = 8 / 16<br/><br/><b>speedup vs. serial = 2.2x</b>
runtime, overall = 624.7ms<br/>single runtimes = (564.3 +/- 107.7) ms<br/>speedup = 7.23x<br/>threads / available = 8 / 16<br/><br/><b>speedup vs. serial = 3.0x</b>

[comment]:RESULTS_END

Expand Down
5 changes: 4 additions & 1 deletion examples/multithreaded/multithreaded.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "multithreaded_thread.h"
#include "jkqtmath/jkqtpstatbasics.h"
#include "jkqtpexampleapplication.h"
#include "jkqtplotter_version.h"

#define NUM_SHOWN_PLOTS 3
#define NUM_PLOTS 8
Expand Down Expand Up @@ -129,7 +130,9 @@ int main(int argc, char* argv[])
const auto iend=md.indexOf("[comment]:RESULTS_END");
qDebug()<<" istart="<<istart<<", iend="<<iend;
if (istart>=0 && iend>istart) {
const QByteArray newResults="[comment]:RESULTS\n\n<u><b>SERIAL RESULTS:</b></u><br/>"+ser_result.toUtf8()
const QByteArray newResults="[comment]:RESULTS\n\n<b>VERSION:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_VERSION)
+"\n<b>BUILD MODE:</b> "+QByteArray(JKQTPLOTTER_VERSION::PROJECT_BUILDTYPE)
+"\n\n<u><b>SERIAL RESULTS:</b></u><br/>"+ser_result.toUtf8()
+"\n\n<u><b>PARALLEL RESULTS:</b></u><br/>\n"+par_result.toUtf8()+"\n\n";
md.replace(istart,iend-istart,newResults);
if (f.open(QFile::WriteOnly)) {
Expand Down
62 changes: 35 additions & 27 deletions lib/jkqtcommon/jkqtpbasicimagetools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ const int JKQTPImageTools::NDEFAULTSTEPS = 5;

QMap<int, JKQTPImageTools::LUTData > JKQTPImageTools::global_jkqtpimagetools_lutstore = JKQTPImageTools::getDefaultLUTs();
int JKQTPImageTools::global_next_userpalette = JKQTPMathImageFIRST_REGISTERED_USER_PALETTE;
std::mutex JKQTPImageTools::lutMutex;
QReadWriteLock JKQTPImageTools::lutMutex;
QStringList JKQTPImageTools::getPredefinedPalettesGlobalList = QStringList();
QStringList JKQTPImageTools::getPredefinedPalettesMachineReadableGlobalList = QStringList();



Expand Down Expand Up @@ -2040,38 +2042,44 @@ bool JKQTPImagePlot_QPairCompareFirst(const QPair<T1, T2> &s1, const QPair<T1, T
}

QStringList JKQTPImageTools::getPredefinedPalettes() {
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
static QStringList sl;

if (sl.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
sl.clear();
for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) {
if (it.key()>=0 && it.key()<=JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE) {
if (it.value().nameT.size()!=0) sl<<it.value().nameT;
else if (it.value().name.size()!=0) sl<<it.value().name;
else sl<<QString(QObject::tr("Palette")+" #"+QString::number(it.key()));
QReadLocker lock(&JKQTPImageTools::lutMutex);

if (getPredefinedPalettesGlobalList.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
lock.unlock();
QWriteLocker lock(&JKQTPImageTools::lutMutex);
if (getPredefinedPalettesGlobalList.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
getPredefinedPalettesGlobalList.clear();
for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) {
if (it.key()>=0 && it.key()<=JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE) {
if (it.value().nameT.size()!=0) getPredefinedPalettesGlobalList<<it.value().nameT;
else if (it.value().name.size()!=0) getPredefinedPalettesGlobalList<<it.value().name;
else getPredefinedPalettesGlobalList<<QString(QObject::tr("Palette")+" #"+QString::number(it.key()));
}
}
}
}
return sl;
return getPredefinedPalettesGlobalList;
}


QStringList JKQTPImageTools::getPredefinedPalettesMachineReadable() {
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
static QStringList sl;

if (sl.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
sl.clear();
for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) {
if (it.key()>=0) {
if (it.value().name.size()!=0) sl<<it.value().name;
else if (it.value().nameT.size()!=0) sl<<it.value().nameT;
else sl<<QString("palette #"+QString::number(it.key()));
QReadLocker lock(&JKQTPImageTools::lutMutex);

if (getPredefinedPalettesMachineReadableGlobalList.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
lock.unlock();
QWriteLocker lock(&JKQTPImageTools::lutMutex);
if (getPredefinedPalettesMachineReadableGlobalList.size()!=JKQTPImageTools::global_jkqtpimagetools_lutstore.size()) {
getPredefinedPalettesMachineReadableGlobalList.clear();
for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) {
if (it.key()>=0) {
if (it.value().name.size()!=0) getPredefinedPalettesMachineReadableGlobalList<<it.value().name;
else if (it.value().nameT.size()!=0) getPredefinedPalettesMachineReadableGlobalList<<it.value().nameT;
else getPredefinedPalettesMachineReadableGlobalList<<QString("palette #"+QString::number(it.key()));
}
}
}
}
return sl;
return getPredefinedPalettesMachineReadableGlobalList;
}


Expand All @@ -2080,7 +2088,7 @@ QStringList JKQTPImageTools::getPredefinedPalettesMachineReadable() {

QString JKQTPImageTools::JKQTPMathImageColorPalette2String(JKQTPMathImageColorPalette p)
{
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
QReadLocker lock(&JKQTPImageTools::lutMutex);
auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.find(p);
if (it==JKQTPImageTools::global_jkqtpimagetools_lutstore.end()) return QString::number(static_cast<int>(p));
else {
Expand All @@ -2091,7 +2099,7 @@ QString JKQTPImageTools::JKQTPMathImageColorPalette2String(JKQTPMathImageColorPa

QString JKQTPImageTools::JKQTPMathImageColorPalette2StringHumanReadable(JKQTPMathImageColorPalette p)
{
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
QReadLocker lock(&JKQTPImageTools::lutMutex);
auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.find(p);
if (it==JKQTPImageTools::global_jkqtpimagetools_lutstore.end()) return QString::number(static_cast<int>(p));
else {
Expand All @@ -2103,7 +2111,7 @@ QString JKQTPImageTools::JKQTPMathImageColorPalette2StringHumanReadable(JKQTPMat

JKQTPMathImageColorPalette JKQTPImageTools::String2JKQTPMathImageColorPalette(const QString &p)
{
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
QReadLocker lock(&JKQTPImageTools::lutMutex);
for (auto it=JKQTPImageTools::global_jkqtpimagetools_lutstore.begin(); it!=JKQTPImageTools::global_jkqtpimagetools_lutstore.end(); ++it) {
if (QString::compare(p, it.value().name, Qt::CaseInsensitive)==0) {
return static_cast<JKQTPMathImageColorPalette>(it.key());
Expand Down Expand Up @@ -2234,7 +2242,7 @@ QVector<QColor> JKQTPImageTools::getColorsforPalette(JKQTPMathImageColorPalette

int JKQTPImageTools::registerPalette(const QString &name, const JKQTPImageTools::LUTType &paletteLut, const QString &nameT)
{
std::lock_guard<std::mutex> lock(JKQTPImageTools::lutMutex);
QWriteLocker lock(&JKQTPImageTools::lutMutex);
int id=JKQTPImageTools::global_next_userpalette++;
JKQTPImageTools::global_jkqtpimagetools_lutstore[id].name=name;
JKQTPImageTools::global_jkqtpimagetools_lutstore[id].nameT=((nameT.size()>0)?nameT:name);
Expand Down
16 changes: 10 additions & 6 deletions lib/jkqtcommon/jkqtpbasicimagetools.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <cfloat>
#include <stdint.h>
#include <QColor>
#include <mutex>
#include <QReadWriteLock>
#include <vector>
#include "jkqtcommon/jkqtcommon_imexport.h"
#include "jkqtcommon/jkqtpmathtools.h"
Expand Down Expand Up @@ -341,16 +341,16 @@ enum JKQTPMathImageColorPalette {
JKQTPMathImagePastel2_STEP, /*!< \image{inline} html palettes/palette_pastel2_step.png */
JKQTPMathImageSet1_STEP, /*!< \image{inline} html palettes/palette_set1_step.png */
JKQTPMathImageSet2_STEP, /*!< \image{inline} html palettes/palette_set2_step.png */
JKQTPMathImageALPHA, /*!< \brief special palette with increasing alpha values */
JKQTPMathImageINVERTED_ALPHA, /*!< \brief special palette with decreasing alpha values */

JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the number of predefined palettes */

JKQTPMathImageUSER_PALETTE=65000, /*!< \brief special value for JKQTPImageTools::array2image(), which signals the usage of a provided user-defined palette */

JKQTPMathImageALPHA=JKQTPMathImageUSER_PALETTE-2, /*!< \brief special palette with increasing alpha values */
JKQTPMathImageINVERTED_ALPHA=JKQTPMathImageUSER_PALETTE-1, /*!< \brief special palette with decreasing alpha values */

JKQTPMathImageFIRST_REGISTERED_USER_PALETTE=JKQTPMathImagePREDEFINED_PALETTES_COUNT, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */
JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE=JKQTPMathImageUSER_PALETTE-10, /*!< \brief the ID of the first user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */
JKQTPMathImageLAST_POSSIBLE_REGISTERED_USER_PALETTE=JKQTPMathImageUSER_PALETTE-10, /*!< \brief the ID of the last user-defined paletted, registered with JKQTPImageTools::registerPalette() or JKQTPImageTools::registerPalettesFromFile() */
};


Expand Down Expand Up @@ -664,8 +664,12 @@ struct JKQTPImageTools {
\see registerPalette() registerPalettesFromFile()
*/
static JKQTCOMMON_LIB_EXPORT int global_next_userpalette;
/** \brief Mutex to protect global_jkqtpimagetools_lutstore and global_next_userpalette */
static JKQTCOMMON_LIB_EXPORT std::mutex lutMutex;
/** \brief storage for the palette names in getPredefinedPalettes() \internal */
static JKQTCOMMON_LIB_EXPORT QStringList getPredefinedPalettesGlobalList;
/** \brief storage for the palette names in etPredefinedPalettesMachineReadable() \internal */
static JKQTCOMMON_LIB_EXPORT QStringList getPredefinedPalettesMachineReadableGlobalList;
/** \brief Mutex to protect global_jkqtpimagetools_lutstore, getPredefinedPalettesGlobalList, getPredefinedPalettesMachineReadableGlobalList and global_next_userpalette */
static JKQTCOMMON_LIB_EXPORT QReadWriteLock lutMutex;


/*! \brief returns data of the default LUTs, used to initialize global_jkqtpimagetools_lutstore
Expand Down
67 changes: 57 additions & 10 deletions lib/jkqtcommon/jkqtpconcurrencytools.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#define JKQTPCONCURRENCYTOOLS_H

#include "jkqtcommon/jkqtcommon_imexport.h"
#include <QReadWriteLock>
#include <QReadLocker>
#include <QWriteLocker>
#include <mutex>

/** \brief template class that wraps any datatype and combines it with a mutex, exposes the lock()/unlock()
Expand All @@ -37,9 +40,39 @@ template <class T>
class JKQTPSynchronized {
public:
/** \brief Mutex used by this temmplate */
typedef std::mutex MutexType;
/** \brief type of a lock_guard for a JKQTPSynchronized<T> */
typedef std::lock_guard<JKQTPSynchronized<T> > Locker;
typedef QReadWriteLock MutexType;

/** \brief type of AdoptLock tag, which is used in ReadLocker and WriteLocker to adopt a pre-locked JKQTPSynchronized<T> */
struct AdoptLockType { explicit AdoptLockType() = default; };
/** \brief tag, which is used in ReadLocker and WriteLocker to adopt a pre-locked JKQTPSynchronized<T> */
static constexpr AdoptLockType AdoptLock { };

/** \brief type of a lock_guard for a JKQTPSynchronized<T> for reading */
class ReadLocker
{
public:
inline ReadLocker(const JKQTPSynchronized<T> &sync) noexcept: m_sync(sync) { m_sync.lockForRead(); };
inline ReadLocker(const JKQTPSynchronized<T> &sync, AdoptLockType) noexcept : m_sync(sync) { };
inline ~ReadLocker() { m_sync.unlock(); }
private:
Q_DISABLE_COPY(ReadLocker)
const JKQTPSynchronized<T> &m_sync;
};

/** \brief type of a lock_guard for a JKQTPSynchronized<T> for writing */
class WriteLocker
{
public:
inline WriteLocker(JKQTPSynchronized<T> &sync) noexcept: m_sync(sync) { m_sync.lockForWrite(); };
inline WriteLocker(JKQTPSynchronized<T> &sync, AdoptLockType) noexcept : m_sync(sync) { };
inline ~WriteLocker() { m_sync.unlock(); }
private:
Q_DISABLE_COPY(WriteLocker)
JKQTPSynchronized<T> &m_sync;
};

/** \brief type of a lock_guard for a JKQTPSynchronized<T> for writing */
typedef JKQTPSynchronized<T>::WriteLocker Locker;
/** \brief contained data type T */
typedef T data_type;
/** \brief default constructor, the internal data is default-initialized */
Expand All @@ -59,18 +92,32 @@ class JKQTPSynchronized {
m_data=std::move(other.m_data);
}

/** \brief locks the internal mutex until unlock() is called,
/** \brief locks the internal mutex for writing, until unlock() is called
*
* \note Use Locker instances to actually lock, using a RAII-idiom, as this is safer than doing this by hand!
* \note Use WriteLocker or Locker instances to actually lock, using a RAII-idiom, as this is safer than doing this by hand!
*/
inline void lock() const {
lockForWrite();
}
/** \brief locks the internal mutex for writing, until unlock() is called
*
* \note Use WriteLocker or Locker instances to actually lock, using a RAII-idiom, as this is safer than doing this by hand!
*/
inline void lockForWrite() const {
m_mutex.lockForWrite();
}
/** \brief locks the internal mutex for writing, until unlock() is called
*
* \note Use WriteLocker or Locker instances to actually lock, using a RAII-idiom, as this is safer than doing this by hand!
*/
inline void lock() {
m_mutex.lock();
inline void lockForRead() const {
m_mutex.lockForRead();
}
/** \brief unlocks the internal mutex from a previous lock() call
/** \brief unlocks the internal mutex from a previous lock(), lockForWrite() or lockForRead() call
*
* \note Use Locker instances to actually lock, using a RAII-idiom, as this is safer than doing this by hand!
*/
inline void unlock() {
inline void unlock() const {
m_mutex.unlock();
}
/** \brief assign a value to the internal data storage, <b>not thread-safe.</b>
Expand Down Expand Up @@ -130,7 +177,7 @@ class JKQTPSynchronized {
/** \brief returns the value in the internal data storage, <b>thread-safe</b>.
*/
inline T get_safe() const {
Locker lck(m_mutex);
ReadLocker lck(this);
return m_data;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/jkqtcommon/jkqtpdrawingtools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,14 +556,14 @@ JKQTPSynchronized<QVector<JKQTPCustomGraphSymbolFunctor> > JKQTPlotterDrawingToo

JKQTPGraphSymbols JKQTPRegisterCustomGraphSymbol(JKQTPCustomGraphSymbolFunctor&& f)
{
JKQTPlotterDrawingTools::SymbolsLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
JKQTPlotterDrawingTools::SymbolsWriteLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore->push_back(std::move(f));
return static_cast<JKQTPGraphSymbols>(static_cast<uint64_t>(JKQTPFirstCustomSymbol)+static_cast<uint64_t>(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore->size()-1));
}

JKQTPGraphSymbols JKQTPRegisterCustomGraphSymbol(const JKQTPCustomGraphSymbolFunctor& f)
{
JKQTPlotterDrawingTools::SymbolsLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
JKQTPlotterDrawingTools::SymbolsWriteLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore->push_back(f);
return static_cast<JKQTPGraphSymbols>(static_cast<uint64_t>(JKQTPFirstCustomSymbol)+static_cast<uint64_t>(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore->size()-1));
}
5 changes: 3 additions & 2 deletions lib/jkqtcommon/jkqtpdrawingtools.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ struct JKQTPlotterDrawingTools {
* \internal
*/
static JKQTCOMMON_LIB_EXPORT JKQTPSynchronized<QVector<JKQTPCustomGraphSymbolFunctor> > JKQTPCustomGraphSymbolStore;
typedef JKQTPSynchronized<QVector<JKQTPCustomGraphSymbolFunctor> >::Locker SymbolsLocker;
typedef JKQTPSynchronized<QVector<JKQTPCustomGraphSymbolFunctor> >::ReadLocker SymbolsReadLocker;
typedef JKQTPSynchronized<QVector<JKQTPCustomGraphSymbolFunctor> >::WriteLocker SymbolsWriteLocker;
};


Expand Down Expand Up @@ -982,7 +983,7 @@ inline void JKQTPPlotSymbol(TPainter& painter, double x, double y, JKQTPGraphSym
painter.drawPath(path);
}
if (symbol>=JKQTPFirstCustomSymbol) {
JKQTPlotterDrawingTools::SymbolsLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
JKQTPlotterDrawingTools::SymbolsReadLocker lock(JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore);
const int idx(static_cast<int>(symbol-JKQTPFirstCustomSymbol));
if (idx>=0 && idx<JKQTPlotterDrawingTools::JKQTPCustomGraphSymbolStore->size()) {
painter.setPen(p);
Expand Down
Loading

0 comments on commit 9662ed2

Please sign in to comment.