Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Thread and C++

1 view
Skip to first unread message

baibaichen

unread,
Mar 30, 2009, 8:06:28 AM3/30/09
to
Hi All

in C++, is the assignment to a primitive variable atomic? for exmpale:

int i;
i++; //atomic?
i +2; //atomic?

thanks

Victor Bazarov

unread,
Mar 30, 2009, 8:35:43 AM3/30/09
to
baibaichen wrote:
> in C++, is the assignment to a primitive variable atomic? for exmpale:
>
> int i;
> i++; //atomic?

You're changing an uninitialised value, which has undefined behavior.

> i +2; //atomic?

That expression has no side effects, so why care if it's atomic or not?

And, no, in the language as it's defined *now* nothing is atomic unless
you're using some kind of language extensions, like OpenMP and its
pragmas. In the upcoming Standard simple operations are not defined as
atomic implicitly, there is a special *library* section on atomic
operations.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Vaclav Haisman

unread,
Mar 30, 2009, 10:06:40 AM3/30/09
to
No.

--
VH

Ioannis Vranos

unread,
Mar 30, 2009, 12:09:22 PM3/30/09
to


Must the above i be defined as volatile in multithreading environments?

Balog Pal

unread,
Mar 30, 2009, 12:34:59 PM3/30/09
to
"Ioannis Vranos" <ivr...@freemail.spam.not.gr>

>>> in C++, is the assignment to a primitive variable atomic? for exmpale:
>>>
>>> int i;
>>> i++; //atomic?
>>> i +2; //atomic?
>> No.
>
>
> Must the above i be defined as volatile in multithreading environments?

Volatile helps little or nothing wrt threads in practice. It tells the
compiler that the value could have changed, but you still have no clue of
the outcome of any read, write or i++ like complex, if at the same time
other thread also access the same object.

You need to use sync primitives (mutex, membar, system-provided atomic ops,
etc) to play safe, and also good understanding of the implications. And a
couple of reviews on any thread interaction-involved code and data...

Ioannis Vranos

unread,
Mar 30, 2009, 2:14:42 PM3/30/09
to

I am talking about the case when mutexes (locks) are used. I am reading about Qt these days, and they
recommend using volatile definitions of built-in types in addition to mutexes, to avoid possible compiler
optimisations that may mess things, and I wonder if the last can be true, since we use mutexes.

Balog Pal

unread,
Mar 30, 2009, 2:51:41 PM3/30/09
to
>> Volatile helps little or nothing wrt threads in practice. It tells the
>> compiler that the value could have changed, but you still have no clue of
>> the outcome of any read, write or i++ like complex, if at the same time
>> other thread also access the same object.
>>
>> You need to use sync primitives (mutex, membar, system-provided atomic
>> ops, etc) to play safe, and also good understanding of the implications.
>> And a couple of reviews on any thread interaction-involved code and
>> data...
>
> I am talking about the case when mutexes (locks) are used. I am reading
> about Qt these days, and they recommend using volatile definitions of
> built-in types in addition to mutexes, to avoid possible compiler
> optimisations that may mess things, and I wonder if the last can be true,
> since we use mutexes.

Inside a critical secition (between a mutex lock/unlock) there is no point
to have volatile.
(As general: keep in mind, that access to volatiles is ordered wrt each
other, but there is no requirement on ordering volatiles wrt
nonnolatiles...)

In order for things to work, your comiler and system must understand the
special of the mutex op. And must not move any code that is inside the
section outside of it. If it does, you are hosed no matter what.


s0s...@gmail.com

unread,
Mar 30, 2009, 3:18:06 PM3/30/09
to
On Mar 30, 6:35 am, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> baibaichen wrote:
> > in C++, is the assignment to a primitive variable atomic? for exmpale:
>
> >  int i;
> >  i++;  //atomic?
>
> You're changing an uninitialised value, which has undefined behavior.
>
> >  i +2; //atomic?
>
> That expression has no side effects, so why care if it's atomic or not?
>
> And, no, in the language as it's defined *now* nothing is atomic unless
> you're using some kind of language extensions, like OpenMP and its
> pragmas.  In the upcoming Standard simple operations are not defined as
> atomic implicitly, there is a special *library* section on atomic
> operations.

How about <signal.h>'s sig_atomic_t (which is likely to be defined as
int anyway)?

Sebastian

Victor Bazarov

unread,
Mar 30, 2009, 3:47:04 PM3/30/09
to

I am not sure I understand the question. How about it what?

The *current* Standard does not say it's "likely to be defined as int".
And the operations on that type are *not* defined [as atomic or even
at all]. AIUI, the explicit guarantee WRT the values of type 'volatile
sig_atomic_t' has nothing to do with adding or incrementing integral
values, and with respect to threads. The guarantees have everything to
do with signals and handlers of those signals. There is but one word
"thread" in the entire current Standard.

The *upcoming* standard has not yet been finalised.

So, please be specific when asking for clarifications.

peter koch

unread,
Mar 30, 2009, 3:57:24 PM3/30/09
to
On 30 Mar., 20:14, Ioannis Vranos <ivra...@freemail.spam.not.gr>
wrote:
> Balog Pal wrote:
> > "Ioannis Vranos" <ivra...@freemail.spam.not.gr>

First let me state that I believe that you are aware that volatile has
no purpose in a multithreaded environment. Using a mutex is necessary
and sufficient in C++ (for C++0x other solutions will be available).
Of course, there might be buggy compilers out there that do not behave
well with optimizations but behave properly when using volatile, but
this is the first time I've heard about such a case. Do they provide
more information?

/Peter

Ioannis Vranos

unread,
Mar 30, 2009, 4:16:40 PM3/30/09
to
peter koch wrote:
>
> First let me state that I believe that you are aware that volatile has
> no purpose in a multithreaded environment. Using a mutex is necessary
> and sufficient in C++ (for C++0x other solutions will be available).
> Of course, there might be buggy compilers out there that do not behave
> well with optimizations but behave properly when using volatile, but
> this is the first time I've heard about such a case. Do they provide
> more information?


The book that mentions this is:

"C++ GUI Programming with Qt 4 (2nd Edition) - The official C++/Qt book":

http://www.qtsoftware.com/developer/books/cpp-gui-programming-with-qt-4-2nd-edition

They also use the style:


#include <QApplication>

int main(int argc, char *argv[])
{
QApplication app(argc, argv);


return app.exec();
}


while I use the style:

#include <cstdlib>

#include <QApplication>


int main(int argc, char *argv[])
{
QApplication app(argc, argv);


if(app.exec()!= 0)
return EXIT_FAILURE;
}


and I thought, I should check out.

Regarding volatiles, in multithreading chapter (Chapter14) the books mentions:


"class Thread: public QThread
{
Q_OBJECT

public:
Thread();

void setMessage(const QString &message);
void stop();


protected:
void run();


private:
QString messageStr;
volatile bool stopped;
};

The Thread class is derived from QThread and reimplements the run() function. It provides two additional
functions: setMessage() and stop().

The stopped variable is declared volatile because it is accessed from different threads and we want to be sure
that it is freshly read every time it is needed. If we omitted the volatile keyword, the compiler might
optimize access to the variable, possibly leading to incorrect results".

s0s...@gmail.com

unread,
Mar 30, 2009, 4:48:41 PM3/30/09
to
On Mar 30, 1:47 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> s0s...@gmail.com wrote:
> > On Mar 30, 6:35 am, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> >> baibaichen wrote:
> >>> in C++, is the assignment to a primitive variable atomic? for exmpale:
> >>> int i;
> >>> i++; //atomic?
> >> You're changing an uninitialised value, which has undefined behavior.
>
> >>> i +2; //atomic?
> >> That expression has no side effects, so why care if it's atomic or not?
>
> >> And, no, in the language as it's defined *now* nothing is atomic unless
> >> you're using some kind of language extensions, like OpenMP and its
> >> pragmas. In the upcoming Standard simple operations are not defined as
> >> atomic implicitly, there is a special *library* section on atomic
> >> operations.
>
> > How about <signal.h>'s sig_atomic_t (which is likely to be defined as
> > int anyway)?
>
> I am not sure I understand the question. How about it what?

Well, as I understand it, sig_atomic_t is an integer type that can be
accessed "as an atomic entity", which means that an operation on it
takes a single machine instruction. (I'm not sure which operations
exactly, but the reference I'm reading mentions "fetching" its value
and assigning a value to it.)

Isn't this what the OP asked about?

> The *current* Standard does not say it's "likely to be defined as int".
> And the operations on that type are *not* defined [as atomic or even
> at all].

Why does it have "atomic" in its name then?

> AIUI, the explicit guarantee WRT the values of type 'volatile
> sig_atomic_t' has nothing to do with adding or incrementing integral
> values, and with respect to threads. The guarantees have everything to
> do with signals and handlers of those signals. There is but one word
> "thread" in the entire current Standard.

It doesn't necessarily relate to threads. The purpose of sig_atomic_t
is to allow a signal handler to manipulate an integer variable with
static storage duration without the risk that the handler is invoked
during an operation on the variable (leaving the variable with a
garbage value).

Sebastian

peter koch

unread,
Mar 30, 2009, 4:58:42 PM3/30/09
to
On 30 Mar., 22:16, Ioannis Vranos <ivra...@freemail.gr> wrote:
> peter koch wrote:
>
[snip]

>
> The book that mentions this is:
>
> "C++ GUI Programming with Qt 4 (2nd Edition) - The official C++/Qt book":
>
> http://www.qtsoftware.com/developer/books/cpp-gui-programming-with-qt...
>
[snip]

>
> Regarding volatiles, in multithreading chapter (Chapter14) the books mentions:
>
> "class Thread: public QThread
> {
>     Q_OBJECT
>
>     public:
>         Thread();
>
>         void setMessage(const QString &message);
>         void stop();
>
>     protected:
>         void run();
>
>     private:
>         QString messageStr;
>         volatile bool stopped;
>
> };
>
> The Thread class is derived from QThread and reimplements the run() function. It provides two additional
> functions: setMessage() and stop().
>
> The stopped variable is declared volatile because it is accessed from different threads and we want to be sure
> that it is freshly read every time it is needed. If we omitted the volatile keyword, the compiler might
> optimize access to the variable, possibly leading to incorrect results".

That is clearly wrong: if the boolean "stopped" is modified using a
mutex only, there is no need for the volatile. What might happen is
that stopped is not modified under the control of a mutex: if the only
change that might take place is a change from false to true, it is my
understanding that such a change will be safe. And even if there might
be perverted situations where this might not be the case, I am
confident that no implementation ever would behave like that.
If we assume that stopped is accessed without using a mutex, it is
possible that the value written by one thread will never propagate to
another. The problem just is that this will not change with volatile.

/Peter

Victor Bazarov

unread,
Mar 30, 2009, 5:29:21 PM3/30/09
to

Convenience?

>
>> AIUI, the explicit guarantee WRT the values of type 'volatile
>> sig_atomic_t' has nothing to do with adding or incrementing integral
>> values, and with respect to threads. The guarantees have everything to
>> do with signals and handlers of those signals. There is but one word
>> "thread" in the entire current Standard.
>
> It doesn't necessarily relate to threads. The purpose of sig_atomic_t
> is to allow a signal handler to manipulate an integer variable

OK, so the C Standard defines 'sig_atomic_t' as integer, and yes, the C
Standard says that those values ("possibly volatile-qualified") "can be
accessed as an atomic entity". This is from C99, which is not supported
by the C++ Standard yet, and I don't have a copy of C90. Are those
defined the same way in C90 (and by inclusion, in C++03)?

I've never seen *a single use* of 'sig_atomic_t' in a program, hopefully
it explains my lack of familiarity with 'sig_atomic_t'.

> with
> static storage duration without the risk that the handler is invoked
> during an operation on the variable (leaving the variable with a
> garbage value).

V

Ioannis Vranos

unread,
Mar 30, 2009, 5:40:43 PM3/30/09
to


Yes it exists in C90 as well. I have placed a draft of C90 (it is the final draft if I remember well)
as a pdf here: http://www.cpp-software.net/temp/c89_draft.pdf


I got it in .txt form, and have converted it to .pdf myself.

Paavo Helde

unread,
Mar 30, 2009, 6:01:42 PM3/30/09
to
Ioannis Vranos <ivr...@freemail.gr> kirjutas:
[...]

> volatile bool stopped;
> };
>
> The Thread class is derived from QThread and reimplements the run()
> function. It provides two additional functions: setMessage() and
> stop().
>
> The stopped variable is declared volatile because it is accessed from
> different threads and we want to be sure that it is freshly read every
> time it is needed. If we omitted the volatile keyword, the compiler
> might optimize access to the variable, possibly leading to incorrect
> results".

This verbiage suggests that 'stopped' is being accessed without mutex. In
general this is a no-no, volatile or not. However, if 'stopped' only
changes state once during the program life-time, and if it is not important
when exactly other threads notice the state change, then this should mostly
work in practice. Using volatile might give some better chances of noticing
the state change, but not much, it would only ensure that the compiler
won't optimize out memory access from a tight loop.

Paavo


Kirit Sælensminde (kayess)

unread,
Mar 31, 2009, 4:32:13 AM3/31/09
to

I've seen a bool marked volatile cause a problem until it had a mutex
controlling access to it. It was pretty rare, maybe one time 50,000
write/reads.

I think the problem comes down to cache coherency -- the volatile may
force a memory read, but there doesn't seem to be any guarantee of
cache write throughs or cache coherency. You'd have to check the
compiler documentation for what it says, or more likely the code
produced to see what it really does.


K

James Kanze

unread,
Mar 31, 2009, 7:06:52 AM3/31/09
to
On Mar 30, 10:48 pm, s0s...@gmail.com wrote:
> On Mar 30, 1:47 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> > s0s...@gmail.com wrote:
> > > On Mar 30, 6:35 am, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> > >> baibaichen wrote:
> > >>> in C++, is the assignment to a primitive variable atomic? for exmpale:
> > >>> int i;
> > >>> i++; //atomic?
> > >> You're changing an uninitialised value, which has undefined behavior.

> > >>> i +2; //atomic?
> > >> That expression has no side effects, so why care if it's
> > >> atomic or not?

> > >> And, no, in the language as it's defined *now* nothing is
> > >> atomic unless you're using some kind of language
> > >> extensions, like OpenMP and its pragmas. In the upcoming
> > >> Standard simple operations are not defined as atomic
> > >> implicitly, there is a special *library* section on
> > >> atomic operations.

> > > How about <signal.h>'s sig_atomic_t (which is likely to be
> > > defined as int anyway)?

> > I am not sure I understand the question. How about it what?

> Well, as I understand it, sig_atomic_t is an integer type that
> can be accessed "as an atomic entity",

Only in certain contexts, for a restricted set of operations.
In fact, I'm not sure that you could call the guarantees
involving it "atomic".

> which means that an operation on it takes a single machine
> instruction.

That's not the definition of atomic. Lot's of operations which
only take a single machine instruction aren't atomic. (A lot of
processors can implement ++ i in a single instruction, provided
the results are not used; I don't know of any where it is
atomic.) And it's quite possible to design atomic operations
involving more than one instruction.

> (I'm not sure which operations exactly, but the reference I'm
> reading mentions "fetching" its value and assigning a value to
> it.)

> Isn't this what the OP asked about?

He mentionned i++, amongst other things. That isn't atomic,
even on a sig_atomic_t.

> > The *current* Standard does not say it's "likely to be defined as int".
> > And the operations on that type are *not* defined [as atomic or even
> > at all].

> Why does it have "atomic" in its name then?

You'd have to ask the people who designed it (or named it).
It's "atomicity" is very restrained.

When you speak about "atomicity", you have to specify the
context somewhat. A lot of operations, for example, will be
"atomic" on a single processor machine, but not if multiple
CPU's are involved. Concerning sig_atomic_t, the C standard
(and the C++ standard, by reference) says that it is the
"integer type of an object that can be accessed as an atomic
entity, even in the presence of asynchronous interrupts." The
only "context" refered to is "the presence of asynchronous
interrupts". Furthermore, it states that "the behavior is
undefined if the signal handler refers to any object with static
storage duration other than by assigning a value to an object
declared as volatile sig_atomic_t, or the signal handler calls
any function in the standard library other than the abort
function, the _Exit function, or the signal function with the
first argument equal to the signal number corresponding to the
signal that caused the invocation of the handler." That's
awfully restrictive.

> > AIUI, the explicit guarantee WRT the values of type
> > 'volatile sig_atomic_t' has nothing to do with adding or
> > incrementing integral values, and with respect to threads.
> > The guarantees have everything to do with signals and
> > handlers of those signals. There is but one word "thread"
> > in the entire current Standard.

> It doesn't necessarily relate to threads. The purpose of
> sig_atomic_t is to allow a signal handler to manipulate an
> integer variable with static storage duration without the risk
> that the handler is invoked during an operation on the
> variable (leaving the variable with a garbage value).

The problem is that the standard doesn't really guarantee this.
The standard doesn't say much of anything about what happens
when you modify sig_atomic_t outside of a signal handler.

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze

unread,
Mar 31, 2009, 7:10:44 AM3/31/09
to
On Mar 30, 11:29 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> s0s...@gmail.com wrote:

[...]


> > It doesn't necessarily relate to threads. The purpose of
> > sig_atomic_t is to allow a signal handler to manipulate an
> > integer variable

> OK, so the C Standard defines 'sig_atomic_t' as integer, and
> yes, the C Standard says that those values ("possibly
> volatile-qualified") "can be accessed as an atomic entity".
> This is from C99, which is not supported by the C++ Standard
> yet, and I don't have a copy of C90. Are those defined the
> same way in C90 (and by inclusion, in C++03)?

Yes.

> I've never seen *a single use* of 'sig_atomic_t' in a program,
> hopefully it explains my lack of familiarity with
> 'sig_atomic_t'.

In a modern, threaded environment, there's really very little
use for it. At least under Unix (but I'm sure the same holds
for Windows), you can set things up so that the signal triggers
a thread, and then do anything you want in that thread (subject
to the usual restrictions). Without threading, it's useful for
things like signaling a request for a clean shutdown: before
activating signals, you set a global sig_atomic_t to 0, then at
various places in the code, you test it, and start a clean
shutdown if it isn't 0. In the signal handler, you set it to 1.

That's really about all that it guaranteed to work.

0 new messages