Thread Safe

R

Roedy Green

I'm still confused ! I don't have much experience in thread programing.
Best way, I guess would be to write a "proof of concept" program which
should indicate that this little piece of code is thread safe or not. I
would like to run this on all JVMs.

It is very difficult to debug thread code. You have to become paranoid
and simply imagine all possible horrible things that could happen and
make sure you have them covered. You can never test enough to cover
all possibilities, especially all possibilities on different hardware,
platforms, oses.

The keys are:

1. keep the threads from meddling the same variables.

2. don't do raw thread/synchronized/wait/notify code. Use classes
that encapsulate that logic. See the concurrent package e.g. Queue

http://mindprod.com/jgloss/queue.html
 
R

Roedy Green

A context switch does not flush registers to their corresponding
variables. If other threads look at those variables, they will be out
of date, unless special measures were taken.
 
R

Roedy Green

And that is the point of the "atomic"
guarantee in the Java language definition.

are non-volatile long writes guaranteed atomic?

IIRC that is not so.

On a Pentium, arranging for longs to be stored atomically with native
threads could be expensive. I'm not sure how you would go about it.
 
B

Benji

Chris said:
reads of the same variable, are atomic, so there is no question of garbage
appearing in that variable. What's more the variable is a latch (is only ever
changed once) so there is no question of race conditions. However, without
without synchronisation in requestStop() and shouldKeepGoing(), there is no
guarantee that changes to m_stopRequested that are made in one thread will
/ever/ be visible to the thread where the worker is running. That counts as
incorrect execution in my book.
Just for completeness, this problem could also be fixed by declaring
m_stopRequested to be "volatile". That might not be a bad option in this very
particular example, but in real world code using explicit synchonisation is
usually the only simple and/or sufficient option.

well, 2 things:
1) this is bad code. =) If you're explicitly waiting on the value of
a variable to be changed, you should use wait/notify, which uses
synchronized, which sould sync the variable.
2) even if you did want to spin-lock, you still have no guarentee that
the thread that sets the variable will ever get run. the OS scheduler
has the option of freezing this thread indefinitely, just like you have
no guarentee that the thread's memory will get synchronized. However,
in practice neither of these are concerns.
 
B

Benji

Chris said:
run()
{
while (! m_stopRequested)
oneStepOfWork();
}

run()
{
bolean aBool = m_stopRequested.
while (! aBool)
oneStepOfWork();
}
and that's a correctness issue. The same observation applies at hardware
level, although I don't know if there are any JVM implementation that run on
hardware (or even if there is any hardware) which defaults to such weak
propogation guarantees.

of course, a loop like that isn't guarenteed not to starve all other processes
in the system. =)

in practice, that's bad programming, and if you actually knew that a spinlock
would be a good solution, you would also be smart enough to know that you
should put a memory barrier inside of the while loop.

However, that's interesting. I didn't think that was a possibility. I was
under the impression that the JVM was not allowed to rewrite field accesses
like that - only local variables. (I thought that fields automatically
had some properties of 'volatile' in that sense) Maybe that's the .NET
framework? Can you find a reference for this behavior? I'm looking in the
JLS and I can't find anything that mentions it. Just the absence of any
mention of it.
 
S

Steve Horsley

Roedy said:
A context switch does not flush registers to their corresponding
variables. If other threads look at those variables, they will be out
of date, unless special measures were taken.

Right.

In theory, thread-1 could call setFoo(1) on Wednesday, thread-2
could call setFoo(2) on Thursday, and thread-1 could call
getFoo() on Friday and find that it's still 1. This is definitely
an issue of timeliness.

Steve
 
S

Steve Horsley

Roedy said:
are non-volatile long writes guaranteed atomic?

IIRC that is not so.

On a Pentium, arranging for longs to be stored atomically with native
threads could be expensive. I'm not sure how you would go about it.

It is my understanding that writes (and reads) of long values are
not guaranteed to be atomic, although all other primitives are
(including object references, of course). I can't find where I
read that now.

Steve
 
T

Thomas Hawtin

Steve said:
It is my understanding that writes (and reads) of long values are not
guaranteed to be atomic, although all other primitives are (including
object references, of course). I can't find where I read that now.

long and double reads and writes are not guaranteed to be atomic,
*except* if they are volatile. However, Sun's JVM for x86 has a bug in
that respect. I'm not entirely sure why they don't just make it slow,
like trig functions.

Tom Hawtin
 
J

John C. Bollinger

Benji said:
1) this is bad code. =) If you're explicitly waiting on the value of
a variable to be changed, you should use wait/notify, which uses
synchronized, which sould sync the variable.

Well, the code isn't guaranteed to work correctly, which was exactly
Chris' point. So yes, it's bad code in that sense. On the other hand,
wait()/notify() is not correct here, because the thread checking for an
update specifically does *not* want to block on the change -- quite the
opposite, it wants to keep going until the change signals it to stop.
This is pretty much the standard idiom for gracefully stopping a running
thread, except that to make it correct you need to synchronize the write
and read (on the same monitor) to ensure that any update is seen by the
reading thread. This, again, is the point: the atomicity of the read
and write are nowhere close to enough to provide thread safety.
2) even if you did want to spin-lock, you still have no guarentee that
the thread that sets the variable will ever get run. the OS scheduler
has the option of freezing this thread indefinitely, just like you have
no guarentee that the thread's memory will get synchronized. However,
in practice neither of these are concerns.

The thread-scheduling issue is less of a concern, I agree, but I think
you are discounting the update visibility much too much.
 
J

John C. Bollinger

Benji said:
Chris said:
run()
{
while (! m_stopRequested)
oneStepOfWork();
}



run()
{
bolean aBool = m_stopRequested.
while (! aBool)
oneStepOfWork();
}
[...]

in practice, that's bad programming, and if you actually knew that a spinlock
would be a good solution, you would also be smart enough to know that you
should put a memory barrier inside of the while loop.

You can't have your cake and eat it too. Your position a few posts ago
seems to have been that it should not be necessary to synchronize
exclusively for the purpose of ensuring that updates are propagated
across threads:

"however, I disagree with the other poster in that I think [atomic reads
and writes] is as thread safe as you can possibly get it - because there
is no case in which you would need the value of foo to be immediately
propagated across threads in which you were not using a synchronized
block, which would propagate the values. I would be very interested if
someone could come up with an example where synchronized would help
anything as far as correctness of a program goes."

Chris responded with just the kind of example you requested, and now
you've effectively said "well, duh, you need to synchronize." If you
have a point left anywhere in there then I'm missing it.
However, that's interesting. I didn't think that was a possibility. I was
under the impression that the JVM was not allowed to rewrite field accesses
like that - only local variables. (I thought that fields automatically
had some properties of 'volatile' in that sense) Maybe that's the .NET
framework? Can you find a reference for this behavior? I'm looking in the
JLS and I can't find anything that mentions it. Just the absence of any
mention of it.

You might want to consider reading chapter 17 of JLS3, especially
sections 17.3 and 17.4. These are all about the things that a
conforming Java program may do with shared variables. The material
probably does not answer your question directly, but it certainly does
support Chris' assertion that a program could behave /as if/ it
performed the optimization he described.
 
R

Roedy Green

long and double reads and writes are not guaranteed to be atomic,
*except* if they are volatile. However, Sun's JVM for x86 has a bug in
that respect. I'm not entirely sure why they don't just make it slow,
like trig functions.

What I'm curious about is what sort of MASM code does Sun generate to
insure a save is atomic if a long is declared volatile? What tools
are available to snoop on Sun's dynamically generated machine code?

Is it as primitive as acquiring a lock that all threads use for all
64-bit saves? Please no!

There are possible problems with 32 bit quantities too. For anyone
unfamiliar with word tearing, here's a good explanation taken from
David R. Butenhof's book, Programming with POSIX Threads.

If a variable crosses the boundary between memory units, which can
happen if the machine supports unaligned memory access, the computer
may have to send the data in two bus transactions. An unaligned 32-bit
value, for example, may be sent by writing the two adjacent 32-bit
memory units. If either memory unit involved in the transaction is
simultaneously written from another processor, half of the value may
be lost. This is called "word tearing."
 
R

Roedy Green

long and double reads and writes are not guaranteed to be atomic,
*except* if they are volatile. However, Sun's JVM for x86 has a bug in
that respect. I'm not entirely sure why they don't just make it slow,
like trig functions.

From the IA-32 Intel Architecture Software Developer's Manual Volume
3 : System Programming Guide

7.1.1 Guaranteed Atomic Operations

The Pentium 4, Intel Xeon, P6 family, Pentium, and Intel486 processors
guarantee that the following basic memory operations will always be
carried out atomically:

.. Reading or writing a byte

.. Reading or writing a word aligned on a 16-bit boundary

.. Reading or writing a doubleword aligned on a 32-bit boundary

The Pentium 4, Intel Xeon, and P6 family, and Pentium processors
guarantee that the following additional memory operations will always
be carried out atomically:

.. Reading or writing a quadword aligned on a 64-bit boundary.

.. 16-bit accesses to uncached memory locations that fit within a
32-bit data bus.

The P6 family processors guarantee that the following additional
memory operations will always be carried out atomically:

.. Unaligned 16-, 32-, and 64-bit accesses to cached memory that fit
within a 32-byte cache line.

Accesses to cacheable memory that are split across bus widths, cache
lines and page boundaries are not guaranteed to be atomic by the
Pentium 4, Intel Xeon, P6 family, Pentium and Intel486 processors. The
Pentium 4, Intel Xeon and P6 family processors provide bus control
signals that permit external memory subsystems to make split accesses
atomic; however, nonaligned data accesses will seriously impact the
performance of the processor and should be avoided.
 
B

Benji

John said:
Well, the code isn't guaranteed to work correctly, which was exactly
Chris' point. So yes, it's bad code in that sense. On the other hand,
wait()/notify() is not correct here, because the thread checking for an
update specifically does *not* want to block on the change -- quite the
opposite, it wants to keep going until the change signals it to stop.

I think that my point was (which I now realize is incorrect) that if you
need to wait on something, the only good way to do it is with a synchronize
and a .wait(). However, now I realize that there are several correct
situations that could be optimized into incorrect code since the JVM is not
aware that a certain bit of code needs to be left as-is.

I think I was perhaps thrown off by the article that made it sound as though
the main problem was delay, which is a bit misleading - but I suppose it
depends on the application.

Thanks for your responses.
 
A

Alun Harford

Benji said:
You might not want to go around telling people to get introductions to
things that you don't understand yourself, luv. :-*

Just because the bytecode operation is one step doesn't mean that it's
going to be translated into one step in the native code that is compiled
by the VM.

The Java Memory Model does not guarentee that double and long will be
written atomically. See

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7

Hmm... my apologies.
I look silly now.

Alun Harford
 
T

Thomas Hawtin

Roedy said:
What I'm curious about is what sort of MASM code does Sun generate to
insure a save is atomic if a long is declared volatile?

It doesn't for x86. That is the bug.

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4023233
What tools
are available to snoop on Sun's dynamically generated machine code?

IIRC, there is code to dump (dis)assembler produced by HotSpot, but
licensing restrictions prevent it being generally available. You
favourite debugger should be able to manage. I just tried gdb, but
couldn't get it to do anything but whinge.
Is it as primitive as acquiring a lock that all threads use for all
64-bit saves? Please no!

The slightly more efficient solution is to take a value based upon the
hash code of the containing object. Use the bottom few bits as an index
into a block of spin locks.
There are possible problems with 32 bit quantities too. For anyone
unfamiliar with word tearing, here's a good explanation taken from
David R. Butenhof's book, Programming with POSIX Threads.

Sun's JVM always aligns objects to eight byte boundaries.

Tom Hawtin
 
R

Roedy Green

Sun's JVM always aligns objects to eight byte boundaries.

but within an object what happens with alignment? Does Sun move all
the doubles to the front of the object and 8-byte align them? From
what I have been reading about tearing with Intel, they had better
align fields.
 
R

Roedy Green

Sun's JVM always aligns objects to eight byte boundaries.

I wonder if there is some way to statically analyse code or
dynamically monitor code running interpretively to detect potential
trouble spots where two different threads look at or write to
variables outside sync blocks.
 

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

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,165
Latest member
JavierBrak
Top