Qt-interest Archive, August 2006
thread-safe read-function for a boolean without locking
Message 1 in thread
Hi,
I would like to add a property "dirty" to a class by having a
read-function dirty() and a write function setDirty().
These property must be thread-safe (it gets read and written by
different threads at the same time). Therefor I lock using a mutex if
m_Dirty gets written by setDirty().
public:
bool dirty() const
{
return m_Dirty;
};
void setDirty(const bool d)
{
m_DirtyMutex.lock();
m_Dirty = d;
m_DirtyMutex.unlock();
};
private:
bool m_Dirty;
QMutex m_DirtyMutex;
I wonder if I have to lock in the read-function dirty(), too.
I do not want to lock in dirty() because than this function wouldn't be
"const" anymore, because it would change the member-variable m_DirtyMutex.
In qt4/examples/threads/mandelbrot/renderthread.cpp line 90 I see, that
you do not have to lock if you want to read a boolean. Is reading a
boolean therefor atomic? -- or is even reading any member atomic?
Thanks for any help,
Greetings
Jens
--
[ signature omitted ]
Message 2 in thread
On Thursday 03 August 2006 11:56, Jens wrote:
> Hi,
>
> I would like to add a property "dirty" to a class by having a
> read-function dirty() and a write function setDirty().
> These property must be thread-safe (it gets read and written by
> different threads at the same time). Therefor I lock using a mutex if
> m_Dirty gets written by setDirty().
>
> public:
> bool dirty() const
> {
> return m_Dirty;
> };
> void setDirty(const bool d)
> {
> m_DirtyMutex.lock();
> m_Dirty = d;
> m_DirtyMutex.unlock();
> };
> private:
> bool m_Dirty;
> QMutex m_DirtyMutex;
>
>
> I wonder if I have to lock in the read-function dirty(), too.
> I do not want to lock in dirty() because than this function wouldn't be
> "const" anymore, because it would change the member-variable m_DirtyMutex.
>
> In qt4/examples/threads/mandelbrot/renderthread.cpp line 90 I see, that
> you do not have to lock if you want to read a boolean. Is reading a
> boolean therefor atomic? -- or is even reading any member atomic?
You can mark m_DirtyMutex to be mutable, then you can do it in a const method.
Cheers
-ian reinhart geiser
--
[ signature omitted ]
Message 3 in thread
Jens said:
> bool m_Dirty;
This should be "volatile bool", so that it is not left in registers for
too long.
> I wonder if I have to lock in the read-function dirty(), too.
> I do not want to lock in dirty() because than this function wouldn't be
> "const" anymore, because it would change the member-variable m_DirtyMutex.
I fear you even designed it wrong - if you base any decisions on dirty()
that could in fact affect this flag again, then no amount of locking
inside it will help you:
For every action which affects this variable you have to lock before the
first read/write and unlock after the last read/write. So if your
algorithm looks like:
if(x.dirty()){
x.makeBackup();
x.setDirty(false);
}
it will fail spectacularly. It should actually be:
x.makeBackupIfDirty();
with this method looking like:
void X::makeBackupIfDirty()
{
QMutexLocker mlock(&mymutex);
if(m_dirty)
makeBackup();
m_dirty=false;
}
(QMutexLocker sets the lock where it is instantiated and clears it on
leaving its range of visibility - ie. it will lock on entering the method
and unlock on leaving it)
Konrad
--
[ signature omitted ]
Message 4 in thread
Hi Konrad, Hi Ian, Hi anybody else,
I have classes which only hold data and I have classes which interact
with these data-classes through read- and write-functions.
Therefor I do not want to start mixing these classes.
But you are right - I still need to think about a way of locking all
write-functions of my data-class before saving the data to disk.
I thought of making a copy of my data-classes first. And after that
saving the data of the copy to disk using a different thread.
It could look like this:
MyData* copy = data.createCopyIfDirtyToSave();
if(copy) {
saveToDisk(copy);
}
The createCopyIfDirtyToSave()-function sets all threads to in wait
condition which call write-functions while the copying is done. After
that m_Dirty becomes false and all threads waiting in a write-function
get woken up.
Would that work?
Greetings
Jens
P.S:
I do not get, why a member must be "volatile" in my case.
-------------------------------------
class MyData : public QObject
{
Q_OBJECT
.....
public:
MyData* createCopyIfDirtyToSave() {
QMutexLocker locker(&m_CopyMutex);
MyData* copy = 0;
m_Copying = true;
if(dirty()) {
MyData* copy = new MyData();
..fill copy with all data of this class..
m_Dirty = false;
}
m_Copying = false;
m_WritingAllowed.wakeAll();
}
void writeDataA(int data)
{
if(m_Copying) m_WritingAllowed.wait();
QWriteLock locker(&m_DataALock);
m_DataA = data;
setDirty(true);
}
int readDataA() const
{
QReadLock locker(&m_DataALock);
return m_DataA;
}
bool dirty() const
{
QReadLock locker(&m_DirtyLock);
return m_Dirty;
};
void setDirty(const bool d)
{
if(m_Copying) m_WritingAllowed.wait();
QWriteLock locker(&m_DirtyLock);
m_Dirty = d;
};
private:
bool m_Copying;
QMutex m_CopyMutex;
QWaitCondition m_WritingAllowed;
int m_DataA;
mutable QReadWriteLock m_DataALock;
bool m_Dirty;
mutable QReadWriteLock m_DirtyLock;
}
Konrad Rosenbaum schrieb:
> Jens said:
>> bool m_Dirty;
>
> This should be "volatile bool", so that it is not left in registers for
> too long.
>
>> I wonder if I have to lock in the read-function dirty(), too.
>> I do not want to lock in dirty() because than this function wouldn't be
>> "const" anymore, because it would change the member-variable m_DirtyMutex.
>
> I fear you even designed it wrong - if you base any decisions on dirty()
> that could in fact affect this flag again, then no amount of locking
> inside it will help you:
>
> For every action which affects this variable you have to lock before the
> first read/write and unlock after the last read/write. So if your
> algorithm looks like:
>
> if(x.dirty()){
> x.makeBackup();
> x.setDirty(false);
> }
>
> it will fail spectacularly. It should actually be:
>
> x.makeBackupIfDirty();
>
> with this method looking like:
>
> void X::makeBackupIfDirty()
> {
> QMutexLocker mlock(&mymutex);
> if(m_dirty)
> makeBackup();
> m_dirty=false;
> }
>
> (QMutexLocker sets the lock where it is instantiated and clears it on
> leaving its range of visibility - ie. it will lock on entering the method
> and unlock on leaving it)
>
>
> Konrad
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with "unsubscribe" in the subject or the body.
> List archive and information: http://lists.trolltech.com/qt-interest/
>
>
--
[ signature omitted ]