[Interest] Heavily Commented Example: Simple Single Frontend with Two BackendsHi,
Daniel Bowen
qtmailinglist1 at bowensite.com
Wed Oct 24 08:08:17 CEST 2012
> >> Let me state for the record that I do not use volatiles for thread
> >> synchronization. But the issue at hand is not whether a volatile
> >> can be used for full-featured thread synchronization, but whether
> >> it can be used by one thread to signal a second looping thread to
> >> quit.
> >
> > It can. In that restricted scenario, even a non-atomic write would
> > be sufficient.
(snip)
> > CPU A writes to the volatile signalling variable, but it writes to its
> > CPU-specific cache. The thread that's looping runs on CPU B, and
> > repeatedly reads from the volatile signalling variable, but always
> > reads it from its own CPU-specific cache. So it never gets the signal
> > to quit, and potentially loops forever.
>
> Well, that's not exactly how processors work. CPU A will eventually get
> to write the data from its cache back to main RAM. And CPU B will
eventually
> get to notice that and discard its cache. So the code running on CPU B
will
> eventually get to see the new value.
>
> The question is only how long that might take.
>
> Also note that you should not implement a busy-wait loop like that, like
> a spinlock. At least on x86, if one CPU is constantly reading from the
same
> address, it will prevent the others from writing to it. Since you're
> busy- looping, you're spending power.
I'm also quite interested in this topic. There are a handful of places where
I've used a similar pattern where one thread is doing a loop, and reading a
stop flag to stop a while loop, and some other thread can write to that stop
flag. That stop flag is a member variable. The loops where I've used it
with a stop variable are not constantly pounding the CPU unnecessarily. For
example, let's say you have a thread that auto saves any changes on a
regular interval, or one that processes "work items" if there are any. And
a QWaitCondition is used to wake up to either do work, or stop. But if
there isn't anything to do, it's doing a smart wait. For example:
while(!m_stop)
{
m_lock.lock();
AutoSave();
if(!m_stop)
{
m_waitCondition.wait(&m_lock, m_autoSaveInterval);
}
m_lock.unlock();
}
With some other method called from another thread like
bool A::stopAndWait(unsigned long timeoutMs)
{
m_stop = true;
m_waitCondition.wakeAll();
return this->wait(timeoutMs);
}
So, in that case, I've typically declared
volatile bool m_stop;
With the intention of using volatile for "don't optimize the read away".
After reading some various links like the Herb Sutter article referenced
earlier, a co-worker believes that volatile in this case is unnecessary.
i.e., just use
bool m_stop;
So, I'd like to understand the possibilities for the best cross-platform
code. Going "one time too many" is OK.
- Is reading and writing to a bool m_stop (no volatile) without a mutex
locked OK? Or could the read of the member variable m_stop realistically be
optimized away?
- Is reading and writing to a volatile bool m_stop without a mutex locked
OK?
- If no locking is OK, is volatile better for m_stop, or does it not matter
(and just causes a little bit slower execution for the read/write of
m_stop)?
- Is not using volatile on bool m_stop OK, but both reading and writing to
m_stop should be done with a mutex locked?
- If m_stop is only read or written with a mutex locked, could the value
ever be stale that is read (causing "one time too many")?
- What if m_stop was QAtomicInt instead of bool?
Thanks!
-Daniel
More information about the Interest
mailing list