PDA

View Full Version : Using QVariant class variable in a thread safe manner.



pkj
9th January 2012, 18:37
I have one Reader and one Writer Thread. Reader reads from class member QVariant val and Writer writes into val. Now I want to do it in a synchronized manner. I implemented in this manner:
itm.h


#ifndef ITM_H
#define ITM_H

#include <QObject>
#include <QVariant>
#include <QMutex>
class Itm : public QObject
{
Q_OBJECT
public:
explicit Itm(QObject *parent = 0);
QMutex mutex;
void setValue(const QVariant& newVal);
QVariant getValue() ;
private:
QVariant val;


};

#endif // ITM_H
}

and itm.cpp


#include "itm.h"
#include <QMutexLocker>
Itm::Itm(QObject *parent) :
QObject(parent)
{
}

void Itm::setValue(const QVariant &newVal)
{
QMutexLocker locker(&mutex);
val = newVal;
}

QVariant Itm::getValue()
{
QMutexLocker locker(&mutex);
return val;
}
Writer thread uses setValue() function and the reader getValue() function. Now the qt documentation says here (http://developer.qt.nokia.com/doc/qt-4.8/threads-reentrancy.html) that "If a function is not marked as thread-safe or reentrant, it should not be used from different threads. If a class is not marked as thread-safe or reentrant then a specific instance of that class should not be accessed from different threads." Now QVariant has not been marked as reentrant in the documentation. So does that mean that the above method I am trying to implement to achieve synchronization is ill-advised, and if used across threads, QVariants is NOT an option. Or I am misinterpreting??

wysota
9th January 2012, 20:24
You are misinterpreting, your code is ok, although you can change it to:


private:
QReadWriteLock mutex;

void Itm::setValue(const QVariant &newVal)
{
QWriteLocker locker(&mutex);
val = newVal;
}

QVariant Itm::getValue()
{
QReadLocker locker(&mutex);
return val;
}

pkj
9th January 2012, 21:18
Doesn't it mean that the statement 'If a function is not marked as thread-safe or reentrant, it should not be used from different threads. If a class is not marked as thread-safe or reentrant then a specific instance of that class should not be accessed from different threads.' should not have been present in the document fore-mentioned? Because essentially I use the operator overload = / or may be setValue of QVariant which is non-reentrant. Does having a different instance of QVariant for each of Itm classes, makes it by default re-entrant?

wysota
9th January 2012, 21:26
The statement actually means (at least in most cases) that since the class/method is not reentrant/thread-safe, you can't use with directly without proper synchronization. So whenever you call any non-const method (or actually a non non-mutable method) on the variant, you should protect it with a mutex. Since reading a half-written object is no fun either, you should be protecting the non-mutable methods too.

pkj
9th January 2012, 21:37
Alright I get it now. One more question. Does this mean if I write a function which multiple threads can run concurrently, which is not re-entrant, can be made thread-safe by use of mutex?

wysota
9th January 2012, 22:00
Technically the answer to your question is "no", because you are incorrectly using the terms reentrant and thread-safe. A reentrant function doesn't have to be thread-safe (and vice-versa).

http://en.wikipedia.org/wiki/Reentrant_(subroutine)
http://en.wikipedia.org/wiki/Thread_safety

Logically, yes, correctly using a mutex can turn a thread-unsafe method into a thread-safe one. Using a mutex can also cause a reentrant function to become not reentrant (using a non-recursive mutex may cause a deadlock when the function is called again by the same thread).