[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