By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,918 Members | 2,246 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,918 IT Pros & Developers. It's quick & easy.

Help a practitioner with atomic access

P: n/a
Ark
Consider

static T foo;
..............
T get_foo(void) { return foo; }

In a multi-threaded (or -tasked) environment, I need to ensure that I
get_foo() grabs T atomically (e.g. is not preempted while accessing foo).

Are there types T for which atomic fetch /guaranteed/ portably? Does the
standard say anything on this? (I'd guess not; concurrency is not a
subject there.)

A related issue: if I modify get_foo() to
T get_foo(void)
{
T temp;
begin_critical(); //whatever it means
temp = foo;
end_critical();
return temp;
}

- and foo is /not/ a volatile, is there a guarantee that temp will be
actually created, filled and returned as written? My fear is that if a
compiler is smart enough to figure out that begin_critical() and
end_critical() do not modify foo, it may optimize the code into

T get_foo(void)
{
begin_critical();
end_critical();
return foo;
}

That I don't want to happen. On the other hand, I'd rather not make foo
volatile because while I am massaging it (within a critical section) I
don't want to turn off optimizations on it.

Any advice to a cornered practitioner?
Thanks,
- Ark


Oct 5 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Ark wrote:
Consider

static T foo;
.............
T get_foo(void) { return foo; }

In a multi-threaded (or -tasked) environment, I need to ensure that I
get_foo() grabs T atomically (e.g. is not preempted while accessing foo).

Are there types T for which atomic fetch /guaranteed/ portably? Does the
standard say anything on this? (I'd guess not; concurrency is not a
subject there.)
The closest you can come is `volatile sig_atomic_t', which
is guaranteed to work as expected w.r.t. signals. But signals
themselves are all set about with implementation-defined fever
trees, and there is no surety -- in the C language itself --
that signal-safety implies thread-safety.
A related issue: if I modify get_foo() to
T get_foo(void)
{
T temp;
begin_critical(); //whatever it means
temp = foo;
end_critical();
return temp;
}

- and foo is /not/ a volatile, is there a guarantee that temp will be
actually created, filled and returned as written? My fear is that if a
compiler is smart enough to figure out that begin_critical() and
end_critical() do not modify foo, it may optimize the code into

T get_foo(void)
{
begin_critical();
end_critical();
return foo;
}

That I don't want to happen. On the other hand, I'd rather not make foo
volatile because while I am massaging it (within a critical section) I
don't want to turn off optimizations on it.

Any advice to a cornered practitioner?
The magic is all in "whatever it means." All C gives you is
the notion of "sequence points," and then it whisks most of the
gift away under the provisions of the "as-if rule."

Other standards extend the C Standard and provide additional
guarantees not found in the C language per se. For example, the
POSIX "Pthreads" standard (I forget the exact number) guarantees
that pthread_mutex_lock() and pthread_mutex_unlock() will behave
as you desire w.r.t. the code executed in between them. It is
the job of the POSIX implementation to make sure this happens the
way you want; that may or may not require constraining some of the
optimizations a non-POSIX C compiler might indulge in.

See comp.programming.threads for much more on these topics;
they're really not about C as such. There you will learn (among
other things) that `volatile' is neither necessary nor sufficient
for what you want to do. Followups set.

--
Eric Sosman
es*****@acm-dot-org.invalid
Oct 5 '06 #2

P: n/a
Ark wrote:
Are there types T for which atomic fetch guaranteed portably? Does the
standard say anything on this? (I'd guess not; concurrency is not a
subject there.)

A related issue: if I modify get_foo() to
T get_foo(void)
{
T temp;
begin_critical(); //whatever it means
temp = foo;
end_critical();
return temp;
}
Standard knows absolutely nothing about threads.

However, in your particular example, which I'm presuming to just be a
contrived example, I can't see how "T temp" is even suspect to being
clobbered by a concurrent action (presuming begin_critical() doesn't create
new threads and pass temp to it, etc.). I'm also figuring that you're
dyn-allocing for temp, otherwise you wouldn't be returning it either.
Oct 5 '06 #3

P: n/a
On Wed, 04 Oct 2006 22:07:06 -0400, Ark <ak*****@macroexpressions.com>
wrote in comp.lang.c:
Consider

static T foo;
.............
T get_foo(void) { return foo; }

In a multi-threaded (or -tasked) environment, I need to ensure that I
get_foo() grabs T atomically (e.g. is not preempted while accessing foo).
If you have questions about multitasking, you really need to take them
to a group that supports your particular platform. The C standard
does not define any support at all for this.
Are there types T for which atomic fetch /guaranteed/ portably? Does the
standard say anything on this? (I'd guess not; concurrency is not a
subject there.)
The closest C comes to defining anything relating to multitasking is
the type sig_atomic_t, defined in <signal.h>, which is an integer type
that can be accessed atomically even in the presence of asynchronous
interrupts. It may need to be volatile for this guarantee, and the C
standard says nothing about whether your particular multitasking
environment is equivalent.
A related issue: if I modify get_foo() to
T get_foo(void)
{
T temp;
begin_critical(); //whatever it means
I have no idea what that means either, ask in platform specific group.
temp = foo;
end_critical();
return temp;
}

- and foo is /not/ a volatile, is there a guarantee that temp will be
actually created, filled and returned as written? My fear is that if a
compiler is smart enough to figure out that begin_critical() and
end_critical() do not modify foo, it may optimize the code into

T get_foo(void)
{
begin_critical();
end_critical();
return foo;
}

That I don't want to happen. On the other hand, I'd rather not make foo
volatile because while I am massaging it (within a critical section) I
don't want to turn off optimizations on it.
Just what terrible effect do you think making it volatile will have on
your program? As to what is or is not possible really depends on your
platform and its implementation of threads. Ask there.
Any advice to a cornered practitioner?
Thanks,
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Oct 5 '06 #4

P: n/a
Ark
Jack Klein wrote:
On Wed, 04 Oct 2006 22:07:06 -0400, Ark <ak*****@macroexpressions.com>
wrote in comp.lang.c:
>Consider

static T foo;
.............
T get_foo(void) { return foo; }

In a multi-threaded (or -tasked) environment, I need to ensure that I
get_foo() grabs T atomically (e.g. is not preempted while accessing foo).

If you have questions about multitasking, you really need to take them
to a group that supports your particular platform. The C standard
does not define any support at all for this.
>Are there types T for which atomic fetch /guaranteed/ portably? Does the
standard say anything on this? (I'd guess not; concurrency is not a
subject there.)

The closest C comes to defining anything relating to multitasking is
the type sig_atomic_t, defined in <signal.h>, which is an integer type
that can be accessed atomically even in the presence of asynchronous
interrupts. It may need to be volatile for this guarantee, and the C
standard says nothing about whether your particular multitasking
environment is equivalent.
>A related issue: if I modify get_foo() to
T get_foo(void)
{
T temp;
begin_critical(); //whatever it means

I have no idea what that means either, ask in platform specific group.
> temp = foo;
end_critical();
return temp;
}

- and foo is /not/ a volatile, is there a guarantee that temp will be
actually created, filled and returned as written? My fear is that if a
compiler is smart enough to figure out that begin_critical() and
end_critical() do not modify foo, it may optimize the code into

T get_foo(void)
{
begin_critical();
end_critical();
return foo;
}

That I don't want to happen. On the other hand, I'd rather not make foo
volatile because while I am massaging it (within a critical section) I
don't want to turn off optimizations on it.

Just what terrible effect do you think making it volatile will have on
your program? As to what is or is not possible really depends on your
platform and its implementation of threads. Ask there.
>Any advice to a cornered practitioner?
Thanks,
Gee... Yes it's easy to shove me to platforms or threads NG but... I
have no threads!
What I have is a small embedded system, a C compiler (IAR EWARM 4.40),
and a smallish RTOS (uC-OS/II) with a in-house-made port to the
platform. The compiler is unaware of this (or any) RTOS (yeah, the
debugger is). I know the habits of the compiler but I'd love my code to
be able to compile and run with a different compiler and/or on a
different target. You know, this portability thingy.
I wonder how much can be achieved in this direction. Turns out, not much...
Thank anyway.
- Ark
Oct 5 '06 #5

P: n/a
>On Wed, 04 Oct 2006 22:07:06 -0400, Ark <ak*****@macroexpressions.com>
>>In a multi-threaded (or -tasked) environment, I need to ensure that I
get_foo() grabs T atomically ...
>Jack Klein wrote:
>If you have questions about multitasking, you really need to take them
to a group that supports your particular platform. The C standard
does not define any support at all for this.
Indeed.

In article <4c******************************@comcast.com>
Ark <ak*****@macroexpressions.comwrote:
>Gee... Yes it's easy to shove me to platforms or threads NG but... I
have no threads!
In that case, you are stuck with platform- and/or compiler-specific.
>What I have is a small embedded system, a C compiler (IAR EWARM 4.40),
and a smallish RTOS (uC-OS/II) with a in-house-made port to the
platform. The compiler is unaware of this (or any) RTOS (yeah, the
debugger is). I know the habits of the compiler but I'd love my code to
be able to compile and run with a different compiler and/or on a
different target. You know, this portability thingy.
I wonder how much can be achieved in this direction. Turns out, not much...
Indeed, essentially none at all.

Or rather: you can (and apparently already have) define(d) your
own "start critical section" and "end critical section" macros
and/or functions, and write ones that work on your particular
compiler-plus-platform combination. Then, if you change one or
both of those, you need only rewrite those macros/functions.

(It turns out that some compilers, e.g., gcc, have general
"compiler-wide" mechanisms for preventing the compiler from moving
instructions across critical-section barriers. Combining these
with platform-specific barriers, such as the "memory barrier"
instruction on SPARCv9 or "eieio" instruction on PowerPC, does the
job. But note that *both* the gcc-specific trick *and* the
platform-specific trick are required here: if you use some other
compiler, even on the same CPU, you may need some other technique.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Oct 5 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.