Dynamic reads without locking.

Harti Brandt brandt at fokus.fraunhofer.de
Wed Oct 8 05:58:09 PDT 2003


On Wed, 8 Oct 2003, Bernd Walter wrote:

BW>On Wed, Oct 08, 2003 at 02:11:12PM +0200, Harti Brandt wrote:
BW>> On Wed, 8 Oct 2003, Bernd Walter wrote:
BW>>
BW>> BW>On Wed, Oct 08, 2003 at 12:12:22PM +0200, Pawel Jakub Dawidek wrote:
BW>> BW>> But I'm not talking about non-atomic reads. What I'm want to show is that
BW>> BW>> even atomic read (without lock) is dangerous in some cases.
BW>> BW>
BW>> BW>The above mtx_lock/read/mt_unlock case doesn't make sense, because it
BW>> BW>only garanties an up to date value, but you cache it in a local
BW>> BW>variable which again brings it out of date when used outside the lock.
BW>>
BW>> You might (for what ever reason) not care that the value gets out of date
BW>> later on, but care that it is correct and consistent in itself. In this
BW>> case, if foo is large (64-bit or a structure) the mtx_lock/read/mtx_unlock
BW>> makes perfect sense because it guarantees that the value is not changed
BW>> while you're copying it (non-atomically).
BW>
BW>We agree here, but the topic was for atomic reads.
BW>If you read a 64 bit value you have to be shure that 64 bit values can
BW>be read atomicaly and if they are also written atomicaly then there is
BW>no reason to worry about the cosistency of the value itself.
BW>I'm not shure if 64 bit values are atomic on all platforms, but they
BW>are on some - at least on alpha.
BW>On all our platforms reading and writing 8, 16 and 32 bit values should
BW>be atomic if they are naturaly aligned - correct me if I'm wrong.
BW>Well if you write a 32 bit value with byte acces (e.g. with byte order
BW>macros), then you are lost even with a atomic 32 bit read.

Well, yes. The original question, however, did non-trivial processing of
the value on the writer side:

	foo = data;
	foo &= mask;

Even if foo is guaranteed to be atomic on your architecture a non locking
reader may slip in just between writing into foo and masking it thus
getting a (semantically) inconsistent or incorrect value. Therefor whether
you need to lock to read even an atomic datatype depends on the atomicity
of all writers with regard to the semantics of the value. Suppose you have
a variable that should only have values between 0 and 31. You may define a

uint8_t foo;

(guaranteeing that the data type itself is atomic). But if a writer sets
foo as above and you read foo without locking, you might get a wrong
value:

mtx_lock(...)
foo = 77;

				->	bar = foo; /* bar is 77 */

foo &= 0x1f;
mtx_unlock(...)

Even if you write

	foo = data & 0x1f

it may not help (one has to understand all that stuff about sequence
points in the C-standard).

So you can go without locking in the reader only if:

  - the datatype is atomic (depends on your architecture)
  - all writers ensure that they write only consistent values to the
    variable

The 2nd point needs very careful thinking in every case.

harti
-- 
harti brandt,
http://www.fokus.fraunhofer.de/research/cc/cats/employees/hartmut.brandt/private
brandt at fokus.fraunhofer.de, harti at freebsd.org


More information about the freebsd-hackers mailing list