Only reading of variable vs. thread synchronisation

H

Hapa

Does only reading (never writing) of a variable need thread synchronisation?
Thanks for help?

PS.
Anybody knows a Visual C++ news group?
 
I

Ian Collins

Hapa said:
Does only reading (never writing) of a variable need thread synchronisation?
Thanks for help?
That depends on whether you depend on the value read being up to date.

c.p.threads is a better place to ask, a similar question was asked there
recently check the archive.
 
J

James Kanze

Does only reading (never writing) of a variable need thread
synchronisation?

Technically, it depends on the system, but under Posix (and I
think Windows as well), as long as no thread writes the object,
no synchronization is needed. As soon as any threat writes, all
accesses (even from threads which don't write) must be
synchronized.
 
H

Helge Kruse

Hapa said:
Does only reading (never writing) of a variable need thread
synchronisation?
Thanks for help?

PS.
Anybody knows a Visual C++ news group?
It depends. When the variable access can be interrupted a thread switch can
occure. If you need more than one instruction to read _the_actual_data_ you
can read one part of the variable before and one after the read. This can
give strange results.

Where you need more than one instruction? Look at this variable named foo:

struct
{
int[100] a;
char b;
} foo;

/Helge
 
G

Gerhard Fiedler

It depends. When the variable access can be interrupted a thread switch
can occure. If you need more than one instruction to read
_the_actual_data_ you can read one part of the variable before and one
after the read. This can give strange results.

Can you explain this more? Maybe an example? (Considering that no writes to
the variable in question occur during the observation period.)

Thanks,
Gerhard
 
H

Helge Kruse

Gerhard Fiedler said:
Can you explain this more? Maybe an example? (Considering that no writes
to
the variable in question occur during the observation period.)

The thread switch can occur at any point of time, after each CPU
instruction. A normal read operation will prepare some address registers and
perform than the memory access. That is no problem, since the variable is at
the same address. But when the size of the variable is greater than the CPU
can fetch in one memory cycle you are in trouble.

See this example with pseudo code. Your variable is a 64 bit integer. You
have a CPU with one 32 bit address register R1 and some 32 bit data
registers R0,R3,R4. Reading the 64 bit integer is performed in this way. For
illustration purposes I use a simple if-statement.

; _int64 some_variable;
; if (0 == some_variable) { do something fatal }

1: move R1,offset some_variable ; loads 32 bit address to R1
2: move R3,@(R1) ; read low 32 bit part
3: move R4,@(R1+4) ; read high 32 bit
4: or R0,R3,R4 ; set any bit in R0 where the bit in R3
or
; R4 is set. R0 is 0 if no bit was set.
5: jump_if_not_zero some_where
6: ; here starts somthing fatal
.....
X: ; this is some_where

Each numbered line is one CPU instruction. The thread switch can occure
after each line.

If some_variable has a zero value, the "do something fatal" block should be
executed. Now lets set some_variable to 0x0000000100000000. Another thread
will decrement some_variable when it gets the CPU. If the thread switch
occures after line 2, you will read the low part of some_variable to R3.
When the working thread gets the CPU again, line 3 is executed. The value of
some_variable is now 0x00000000FFFFFFFF.

You will see that R3 is 0 since the low part was 0 before the thread switch
and R4 is 0 since the high part is 0 after the thread switch. You would say,
that some_variable was never zero four hours. But "do something fatal" will
be executed in the case. -- unexpected, unsecure, not threadsafe.

Regards,
Helge
 
J

James Kanze

On 2008-06-04 15:59:30, James Kanze wrote:
As soon as any threat writes, [...]
thread === threat ? :)

Now there's a freudian slip if I ever saw one. Threads do
introduce additional complexity, especially with regards to
ensuring correctness, and shouldn't be used unless the cost of
avoiding them outweighs this cost. (Like a lot of other
things---DLL's, TMP, etc.---, there seems to be a mode of using
them systematically, in every application, when a lot of the
time, you can do very well without them, with the results an
application that is simpler and more robust.)
 
J

James Kanze

The thread switch can occur at any point of time, after each
CPU instruction.

We all know that, but it's irrelevant here. The question
concerned what happens if no one writes to the variable. If no
thread modifies the variable, Posix (and Windows as well, I
think) guarantees that non-synchronized accesses work. You
don't need to know or understand more than that---the compiler
will do whatever is necessary for them to work. If any thread
modifies the variable, both Posix and Windows require
synchronization. Even if the variable is in a single machine
word (something you really can't know). Whether the variable is
in a single machine word or not is totally irrelevant here.
 
H

Helge Kruse

We all know that, but it's irrelevant here. The question
concerned what happens if no one writes to the variable.

Probably we will have to ask the OP what the question concerned. I
understand that
- there are threads
- one thread is only reading
- it's in question if the reading threads need any synchronization.

My common understanding of variables are use to store data, so they will be
written sometimes. We would use a constant instead if they are not written.
Since threads are in question I assumed that a write access can occur in
another thread. I read the (never writing) related to the the current
thread.

Hapa, can you clearify?
If any thread modifies the variable, both Posix and Windows
require synchronization. Even if the variable is in a single
machine word (something you really can't know). Whether the
variable is in a single machine word or not is totally
irrelevant here.

I disagree. After you have read a variable you have a copy of it (at least
to a CPU register). You have to define if a change after the read is
acceptible or not. Of not you need a thread synchronization. But even if it
is acceptible you can get in trouble as shown.

The compiler defines how data is stored. The statement, if a variable is in
a single word is compiler and CPU dependend. But you can know.


Regards,
Helge
 
H

Hapa

This variable is using something like global memory. This memory is written
by a third party app, which takes care that, we have no collision between
two apps. But now I have two or more threads whitin my app, which will only
read this global memory.

HP
 
J

James Kanze

Probably we will have to ask the OP what the question concerned. I
understand that
- there are threads
- one thread is only reading
- it's in question if the reading threads need any synchronization.

The question said "only reading, never writing".
My common understanding of variables are use to store data, so
they will be written sometimes.

Before threading is started, for example. I have a lot of
variables which are only read, never written, once threading has
started.
We would use a constant instead if they are not written.

Unless they need some sort of initialization, which can't be
done until main has been entered.

In practice, of course, a lot of the time, the variables will be
const.
Since threads are in question I assumed that a write access
can occur in another thread. I read the (never writing)
related to the the current thread.

That's not the way I interpreted his question, but I agree that
it could have been clearer.
Hapa, can you clearify?
I disagree.

You disagree with Posix?
After you have read a variable you have a copy of it (at least
to a CPU register). You have to define if a change after the
read is acceptible or not. Of not you need a thread
synchronization. But even if it is acceptible you can get in
trouble as shown.
The compiler defines how data is stored. The statement, if a
variable is in a single word is compiler and CPU dependend.
But you can know.

For a given compiler, on a given machine, you can sometimes
know. But it's irrelevant. Even if the variable is in a single
machine word, you need external synchronization. All Posix
offers here are the pthread_... functions; under Solaris, on a
Sparc, I'll occasionally drop down to assembler, and insert a
membar function myself, but only if it's really, really
necessary. And the compilers I use will never, under any
conditions, generate any membar instruction. (On IA-32
architecture, I think that the lock prefix---implied on the xchg
instruction, will automatically set up some sort of fence. But
again, it's never generated by the compiler, so you either have
to use inline assembler, or one of the system primitives.)
 
J

James Kanze

This variable is using something like global memory. This
memory is written by a third party app, which takes care that,
we have no collision between two apps. But now I have two or
more threads whitin my app, which will only read this global
memory.

Which still isn't too clear: by global memory, do you mean
shared memory, with the third party application in a separate
process? And when you say that there is no collision between
the applications, do you mean that there will never be two
processes accessing this shared memory at the same time? If
your process has exclusive access to this shared memory, there
is no need for any synchronization between threads within the
process; all the memory synchronization you need has occured
when you acquired access to the shared memory. (At least under
Posix; I'll less sure about Windows.)
 
H

Helge Kruse

The question said "only reading, never writing".
And it said thread synchronization.
That's not the way I interpreted his question, but I agree
that it could have been clearer.
Yes, we are interpreting something. Probably we do it in a wrong way.
You disagree with Posix?
No, never wrote this, I never cited Posix. I disagree that the single memory
access is irrelevant. The fact if you have single memory access it
determines the robustness of the read operation.
With a single memory access it is just impossible that the problem I
described.
For a given compiler, on a given machine, you can sometimes
know.
You're right. But that's not "something you really can't know". Well, you
said you can know.
But it's irrelevant. Even if the variable is in a single
machine word, you need external synchronization.
If a read operation is in a single memory read operation, what do you want
to synchronize?
I'll occasionally drop down to assembler, and insert a
membar function myself...
Sorry, dont know this membar function.
(On IA-32 architecture, I think that the lock prefix---implied
on the xchg instruction, will automatically set up some sort of fence.
Yes, the lock prefix can avoid interrupt (and thread switch) for an
instruction.
No, the xchg instruction is only used for read and modify. The question
concerned a read-only access.

Regards,
Helge
 
J

Jerry Coffin

[ ... ]
Threads do
introduce additional complexity, especially with regards to
ensuring correctness, and shouldn't be used unless the cost of
avoiding them outweighs this cost.

Threads _often_ introduce cost -- then again, at times, they make a
design substantially _simpler_, particularly if the fundamental design
involves a lot of separate actions that rarely interact, and then only
in clearly specified ways.

Unfortunately, quite a few jobs aren't amenable to such a decomposition.
Even among those that are, the people writing the software may not use
it -- sometimes intentionally, others just because they missed it.
 
J

James Kanze

news:464682ca-4575-4bf2-90b8-a792c2312b5e@k13g2000hse.googlegroups.com...

[...]
No, never wrote this, I never cited Posix.

But I did. The Posix standard says that whether the memory
accessed is a single word or not is irrelevant. If you
disagree, then you disagree with the Posix standard.
I disagree that the single memory access is irrelevant. The
fact if you have single memory access it determines the
robustness of the read operation.

Conforming to the specifications of your platform and your OS
determines the robustness of the read operation. Some platforms
may give you special guarantees for single word accesses;
Sparcs under Solaris don't, however, and as far as I know, nor
do Intels under Windows. If you know otherwise, you're free to
point me to the documentation which specifies it---I've been
looking for something more detailed and precise for Windows for
a long time now.
With a single memory access it is just impossible that the
problem I described.

What problem? Whether the data is in a single word or not, you
don't have any guarantee from Posix that it will work.
You're right. But that's not "something you really can't
know". Well, you said you can know.

You can know whether the data is on a single word, or not,
sometimes, although such guarantees are rare. You can't know
whether that will help.
If a read operation is in a single memory read operation, what
do you want to synchronize?
Memory.
Sorry, dont know this membar function.

It's the Sparc equivalent of a fence. It's used to synchronize
memory.
Yes, the lock prefix can avoid interrupt (and thread switch)
for an instruction.

At least on recent Intel processors, it does a lot more; it
generates some sort of implicit fence, ensuring memory
synchronization.
No, the xchg instruction is only used for read and modify.

And it has an implicit lock prefix, at least on more recent
Intel processors. (This means that a single xchg instruction
will probably be slower than a series of mov instructions if you
don't need the synchronization.)
 
I

Ian Collins

No, never wrote this, I never cited Posix. I disagree that the single memory
access is irrelevant. The fact if you have single memory access it
determines the robustness of the read operation.
With a single memory access it is just impossible that the problem I
described.
Aside from the standards issues already raised, consider a single
*misaligned* memory access requiring more than one bus cycle. A context
switch may occur during such a read.
 
J

James Kanze

Aside from the standards issues already raised, consider a
single *misaligned* memory access requiring more than one bus
cycle. A context switch may occur during such a read.

Note that the problem can be extremely complex. Some hardware
doesn't support byte reads and writes (at the memory access
level): writing a char involves reading the word, replacing the
byte in question, then rewriting it. There was some discussion
during standardization about what to do about those---in the
end, the decision was that the implementation has to make them
work, one way or another. Which may mean some form of locking
and external synchronization on some machines. (On the other
hand, individual bit fields in a common structure are *NOT*
independent objects.)
 

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
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top