PDA

View Full Version : Ways to share data between threads



AndresBarbaRoja
11th March 2011, 12:12
Hi, I need to share some variables between several treads and I'm not really sure about how to do it.
Right now i think i can create a class to store the values and write the setters and getters with the lock mechanisms to protect the variables. Then i can pass a reference to the container object to all the involved threads.
Would this be an effective way to share?
The storage class would be like this:
-header:


#ifndef DATATABLE_H
#define DATATABLE_H

#include <QObject>
#include <QReadWriteLock>

class DataTable : public QObject
{
Q_OBJECT
public:
explicit DataTable(QObject *parent = 0);
void setIntegerData(int);
int getIntegerData();

private:
int integerdata;
QReadWriteLock lock;
};

#endif // DATATABLE_H


-implementation:

#include "datatable.h"


DataTable::DataTable(QObject *parent) :
QObject(parent)
{
}

void DataTable::setIntegerData(int i)
{
QWriteLocker wlocker(&lock);
integerdata=i;
}

int DataTable::getIntegerData()
{
QReadLocker rlocker(&lock);
return integerdata;
}

wysota
11th March 2011, 12:22
If the class inherits QObject then that's not enough. But so far your class doesn't use its QObject legacy for anything so you can just remove the inheritance.

unit
11th March 2011, 13:07
Use QSharedMemory class

Don't make bicycle

AndresBarbaRoja
11th March 2011, 13:09
Thanks. I do not see anything that forces me to inherit QObject so that will go away. So after fixing that, can I consider this class to be thread safe or at least safe enough for my purposes?
Just to learn more, why would this protection be insufficient? Right now I'm using in another part of the code a QQueue which is a member of a QThread. These two do inherit from QObject, so is my app in danger?

wysota
11th March 2011, 13:19
Thanks. I do not see anything that forces me to inherit QObject so that will go away. So after fixing that, can I consider this class to be thread safe or at least safe enough for my purposes?
Yes.


Just to learn more, why would this protection be insufficient?
Because QObject is not thread-safe and since you don't have access to internals of QObejct, you can't protect your class from concurrent access. As long as you don't any QObject API this doesn't matter but then it doesn't make sense to inherit QObject in the first place.


Right now I'm using in another part of the code a QQueue which is a member of a QThread. These two do inherit from QObject, so is my app in danger?
QQueue doesn't inherit QObject. But it's also not thread-safe.

AndresBarbaRoja
11th March 2011, 14:03
QQueue doesn't inherit QObject. But it's also not thread-safe.
Well, I block access to the queue before actually doing anythong to it, so i guess is the same as if it were an int :D
Thanks for the replies
(to both of you)

Added after 22 minutes:


Use QSharedMemory class

Don't make bicycle

I'm reading the QSharedMemory docs but it appears to me that I lock the whole memory and not just parts. If it does not allow me to lock only one variable at a time i'll have to create a shared memory for each (or at least for groups of variables).
I believe I currently need to define serval locks to provide protected access to different variables at the same time. Do you know if defining several shared memory instances would be worthy?
And what does "bicycle" means? I am not a programmer (yet) so i lack a lot of concepts :S

AndresBarbaRoja
11th March 2011, 16:21
More changes!
Since I need to protect each variable i've defined a template class to create a single protected variable:

#ifndef PROTECTEDVARIABLE_H
#define PROTECTEDVARIABLE_H

#include <QReadWriteLock>

template <class T> class ProtectedVariable
{
public:
ProtectedVariable(T=0);
void set(T);
T get();

private:
T value;
QReadWriteLock lock;
};

template <class T> ProtectedVariable<T>::ProtectedVariable(T data)
{
set(data);
}

template <class T> void ProtectedVariable<T>::set(T value)
{
QWriteLocker wlocker(&lock);
this->value=value;
}

template <class T> T ProtectedVariable<T>::get()
{
QReadLocker rlocker(&lock);
return value;
}
#endif // PROTECTEDVARIABLE_H
Then in the data container I create the different variables.

#include <protectedvariable.h>

class DataTable
{
public:
ProtectedVariable<int> data;
ProtectedVariable<double> differentData;
}


Now the question, when I access the variables as


DataTable dt;
dt.data.set(5);

Is my variable still really protected?

wysota
11th March 2011, 16:34
Change your get methods to return a const reference instead of a copy if possible.

Honestly I'm not sure your approach is a good idea. It's usually better to have a single mutex that guards access to a group of variables used together instead of having several mutexes to protect each variable separately. It might happen that you'll end up with a situation where two threads are walking the same code path and accessing the same protected variables in sequence and the "second" thread stops at every possible mutex along the way. Locking mutexes is quite expensive in terms of cpu usage.

As for integers it's better to use QAtomicInt instead of protecting an integer variable with a mutex.

AndresBarbaRoja
11th March 2011, 16:47
Thanks for the insight, I have a lot to learn.
In fact I think some variables can be grouped. I have to think how it can be done though.
Maybe I can create several data storage objects... anyway, it's Friday afternoon! time to disconnect at least for a couple of hours ;)