Thread and C++

B

baibaichen

Hi All

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

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

thanks
 
V

Victor Bazarov

baibaichen said:
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
 
V

Vaclav Haisman

baibaichen wrote, On 30.3.2009 14:06:
Hi All

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

int i;
i++; //atomic?
i +2; //atomic?
No.
 
B

Balog Pal

Ioannis Vranos said:
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...
 
I

Ioannis Vranos

Balog said:
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.
 
B

Balog Pal

Volatile helps little or nothing wrt threads in practice. It tells the
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.
 
S

s0suk3

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


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
 
V

Victor Bazarov

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?

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.

V
 
P

peter koch

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.

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
 
I

Ioannis Vranos

peter said:
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".
 
S

s0suk3

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
 
P

peter koch

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
 
V

Victor Bazarov

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?
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
 
I

Ioannis Vranos

Victor said:
(e-mail address removed) 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?
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).


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.
 
K

Kirit Sælensminde (kayess)

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.

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
 
J

James Kanze

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.
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.
 
J

James Kanze

(e-mail address removed) wrote:

[...]
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,428
Latest member
RosalieQui

Latest Threads

Top