Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this code as thread safe as it can be?

11 views
Skip to first unread message

Peter Olcott

unread,
Jan 5, 2002, 12:43:00 AM1/5/02
to
http://home.att.net/~olcott/FastString.cpp
I would like a complete review, but, the most
crucial issue is the c_str() member function.
It writes an ASCII null to the end of a string.
Can multiple simultaneous threads (from
possibly different processors) all invoke
this function simultaneously without getting
in each others way?


David Schwartz

unread,
Jan 5, 2002, 12:45:49 AM1/5/02
to
Peter Olcott wrote:

What do you mean by thread safe? No, multiple simultaneous threads
can't invoke *any* functions on instances of your FastString class
without appropriate locking. Assuming you're talking PTHREADS, all
accesses to shared objects require appropriate locking and your class
doesn't provide any. Not that this is wrong, this is probably right. The
code that uses this class should provide the appropriate locks.

DS

CBFalconer

unread,
Jan 5, 2002, 6:41:13 AM1/5/02
to

This smells like the wrong question. Any function can be written
to be thread safe by ensuring that all the data is purely local.
However, if the same data is used in multiple threads (an instance
of the class above) there are obvious conflicts. Passing
references or quasi-references (in the form of pointers) can foul
things up.

Ultimately there is no such thing as 'purely local', when you get
right down to the basics. But the various languages and
conventions make it fairly easy to emulate locality.

--
Chuck F (cbfal...@yahoo.com) (cbfal...@XXXXworldnet.att.net)
Available for consulting/temporary embedded and systems.
(Remove "XXXX" from reply address. yahoo works unmodified)
mailto:u...@ftc.gov (for spambots to harvest)


Peter Olcott

unread,
Jan 5, 2002, 8:43:44 AM1/5/02
to

"David Schwartz" <dav...@webmaster.com> wrote in message news:3C36930D...@webmaster.com...

> Peter Olcott wrote:
>
> > http://home.att.net/~olcott/FastString.cpp
> > I would like a complete review, but, the most
> > crucial issue is the c_str() member function.
> > It writes an ASCII null to the end of a string.
> > Can multiple simultaneous threads (from
> > possibly different processors) all invoke
> > this function simultaneously without getting
> > in each others way?
>
> What do you mean by thread safe? No, multiple simultaneous threads
> can't invoke *any* functions on instances of your FastString class
> without appropriate locking. Assuming you're talking PTHREADS, all

I haven't had a whole lot of experience with threading. The only
experience that I have had was spawning a thread in MSDOS
3.1 (a single threaded OS), from scratch, using the timer tick
interrupt vector. What I remember about multiple simultaneous
access to data, is that anything can read anything at the same
time without error, it is only when two or more processes
(or threads) thy to write to the same thing at the same time,
that problems can occur. The locking should only be in this
latter case. What I am talking about here is at a lower
level that may typically be discussed here. I am not so
much interested in software conventions, as I am interested
in what happens at the hardware level. If two or more
processes (or threads) write an ASCII zero to the same
location in memory at the same time, does it get written?
In other words does it get correctly written without
any locks?

Peter Olcott

unread,
Jan 5, 2002, 8:48:05 AM1/5/02
to

"CBFalconer" <cbfal...@yahoo.com> wrote in message news:3C36DAFA...@yahoo.com...

> David Schwartz wrote:
> >
> > Peter Olcott wrote:
> >
> > > http://home.att.net/~olcott/FastString.cpp
> > > I would like a complete review, but, the most
> > > crucial issue is the c_str() member function.
> > > It writes an ASCII null to the end of a string.
> > > Can multiple simultaneous threads (from
> > > possibly different processors) all invoke
> > > this function simultaneously without getting
> > > in each others way?
> >
> > What do you mean by thread safe? No, multiple simultaneous threads
> > can't invoke *any* functions on instances of your FastString class
> > without appropriate locking. Assuming you're talking PTHREADS, all
> > accesses to shared objects require appropriate locking and your class
> > doesn't provide any. Not that this is wrong, this is probably right.
> > The code that uses this class should provide the appropriate locks.
>
> This smells like the wrong question. Any function can be written
> to be thread safe by ensuring that all the data is purely local.
> However, if the same data is used in multiple threads (an instance
> of the class above) there are obvious conflicts. Passing
> references or quasi-references (in the form of pointers) can foul
> things up.

Can two or more different threads (or processes) write
an ASCII zero to exactly the same physical location in
memory (a single byte) without any locks, and have
this write occur correctly even if does this literally at the
same instant by two or more physical processors?

Chris Smith

unread,
Jan 5, 2002, 10:38:39 AM1/5/02
to
Peter Olcott wrote ...

> I haven't had a whole lot of experience with threading. The only
> experience that I have had was spawning a thread in MSDOS
> 3.1 (a single threaded OS), from scratch, using the timer tick
> interrupt vector. What I remember about multiple simultaneous
> access to data, is that anything can read anything at the same
> time without error, it is only when two or more processes
> (or threads) thy to write to the same thing at the same time,
> that problems can occur. The locking should only be in this
> latter case. What I am talking about here is at a lower
> level that may typically be discussed here. I am not so
> much interested in software conventions, as I am interested
> in what happens at the hardware level.

If you are truly interested in what happens at the hardware level, then
your question is terribly inadequate. There are many quite different
common platforms. What happens on one platform is very different from
what happens on another.

It is, of course, possible to write code that is incorrect from a POSIX
standpoint because you don't provide locking, but which happens to work
on a specific compiler/hardware combination. You have a *very* long way
to go before you've managed to provide enough information for anyone to
evaluate whether you've done so, and it appears from what you wrote
above that you've got a very long way to go before you've learned enough
about modern hardware architectures to have a shot at doing it right.

Some concerns involve:

1. How will the compiler reorder memory instructions during optimization?
2. How will the processor reorder or combine memory instructions?
3. What is the memory caching architecture?

Chris Smith

Peter Olcott

unread,
Jan 5, 2002, 11:14:29 AM1/5/02
to
> It is, of course, possible to write code that is incorrect from a POSIX
> standpoint because you don't provide locking, but which happens to work
> on a specific compiler/hardware combination. You have a *very* long way
> to go before you've managed to provide enough information for anyone to
> evaluate whether you've done so, and it appears from what you wrote
> above that you've got a very long way to go before you've learned enough
> about modern hardware architectures to have a shot at doing it right.
>
> Some concerns involve:
>
> 1. How will the compiler reorder memory instructions during optimization?
> 2. How will the processor reorder or combine memory instructions?
> 3. What is the memory caching architecture?

What I am thinking is that all of these considerations become
moot iff (if and only if) we are talking about writing the same
value to the same physical address. The only case where I
could see that there might be a problem, is if the size of
a memory granule is LESS than a single byte.


David Anderson

unread,
Jan 5, 2002, 11:44:07 AM1/5/02
to
> What I am thinking is that all of these considerations become
> moot iff (if and only if) we are talking about writing the same
> value to the same physical address. The only case where I
> could see that there might be a problem, is if the size of
> a memory granule is LESS than a single byte.

If I were you, I'd consider this: "When in doubt, leave no door open to
Murphy".
Therefore, as you do not know what the machine does to your code before
it can be executed, consider this situation to be no different from
another, and lock the memory region.

David Anderson

Peter Olcott

unread,
Jan 5, 2002, 3:20:37 PM1/5/02
to
> If I were you, I'd consider this: "When in doubt, leave no door open to
> Murphy".
> Therefore, as you do not know what the machine does to your code before
> it can be executed, consider this situation to be no different from
> another, and lock the memory region.

I can't possibly do this because my code is a platform
independent thus completely portable version of std::string.
I implemented a fastest possible subset of the functionality
of std::string, and this must be written to be completely
platform independent, as the only means of distribution
is C++ source code, and this code must run unmodified
across every possible platform. every locking mechanism
is completely platform specific, thus breaks my design
requirements.


Arnold Hendriks

unread,
Jan 5, 2002, 3:49:40 PM1/5/02
to
In comp.programming.threads Peter Olcott <olc...@worldnet.att.net> wrote:
> I can't possibly do this because my code is a platform
> independent thus completely portable version of std::string.
> I implemented a fastest possible subset of the functionality
> of std::string, and this must be written to be completely
> platform independent, as the only means of distribution
> is C++ source code, and this code must run unmodified
> across every possible platform. every locking mechanism
> is completely platform specific, thus breaks my design
> requirements.
Then your design requirements are incompatible, and will need to be revised
The C++ standard does not know about threads. Threaded code cannot comply
with standard C++, and even then, the C++ standard does not give you the
required memory model guarantees and function primitives to implement
thread-safe code.

Of course, there is no problem to be as much standard C++ compliant,
and as much thread-safe as possible. But you _have_ to make a design
trade-off. Especially when you're doing what you're trying to do: writing
code that is not guaranteed to be thread-safe on all platforms to gain
an optimization (delaying the setting of the NUL-byte).

There's nothing inherently wrong with that, but you must accept a
(small?) loss of portability.

--
Arnold Hendriks <a.hen...@b-lex.com>
B-Lex Information Technologies, http://www.b-lex.com/

Ian Lazarus

unread,
Jan 5, 2002, 4:23:09 PM1/5/02
to
I don't see what the huballoo is about. If two threads are writing the same
value to the same memory location, how can there be a problem, even if the
memory write is non-atomic.


Peter Olcott

unread,
Jan 5, 2002, 4:27:26 PM1/5/02
to

"Ian Lazarus" <nob...@nowhere.net> wrote in message
news:19KZ7.327089$W8.12...@bgtnsc04-news.ops.worldnet.att.net...

> I don't see what the huballoo is about. If two threads are writing the same
> value to the same memory location, how can there be a problem, even if the
> memory write is non-atomic.

I don't see why either, but, then I am not an expert in this area.


Peter Olcott

unread,
Jan 5, 2002, 4:30:18 PM1/5/02
to
> Of course, there is no problem to be as much standard C++ compliant,
> and as much thread-safe as possible. But you _have_ to make a design
> trade-off. Especially when you're doing what you're trying to do: writing
> code that is not guaranteed to be thread-safe on all platforms to gain
> an optimization (delaying the setting of the NUL-byte).
>
> There's nothing inherently wrong with that, but you must accept a
> (small?) loss of portability.

What I am thinking is that this hypothetical loss, might
only be hypothetical, and in actuality there are no
machines that exist where this would present an actual
problem. The existence of one machine that does
have this problem would refute this tentative claim.


Jeff Greif

unread,
Jan 5, 2002, 4:36:57 PM1/5/02
to
Because it's the wrong question. Two simultaneously executing calls to
c_str are a much more benign case than many other kinds of contention.
One thread could write the null byte for c_str, while another one could
write 5 more bytes starting at the null byte. Then, before the second
thread could stick another null byte on the new end, the first thread
could use the supposedly null-terminated string and dereference bytes
off into hyperspace. Or the first thread's null byte could be written
in the middle of the 5 bytes the other thread is writing, because the
first thread could read NextByte and then be interrupted by the second
thread.

There has to be some locking imposed from outside, or the implementation
of c_str must be different.

Jeff


"Ian Lazarus" <nob...@nowhere.net> wrote in message
news:19KZ7.327089$W8.12...@bgtnsc04-news.ops.worldnet.att.net...

David Anderson

unread,
Jan 5, 2002, 4:40:15 PM1/5/02
to
> I don't see what the huballoo is about. If two threads are writing the same
> value to the same memory location, how can there be a problem, even if the
> memory write is non-atomic.

The problem is about race conditions. If these threads write a 0 to a
memory address, that would mean that at some point they write something
else to that location (so it can later be reset).

Imagine then that one thread tests the memory, finds it empty
(writable), is preempted in favour of the second thread which does the
same check and happily writes a value that'll be squashed as soon as the
first thread regains control and writes it's value. You here have a
problem: each thread believes it has done it's duty by writing to that
address, but thread 2's data is lost.

That is one big rule when programming threads: always consider the worst
case scenario, because with millions of iterations a second the worst
case scenario has a very high probability of turning up for tea and crashes.

But to determine if there is a risk of race conditions, it must be
determined in what circumstances these 0s are being written (after some
synchronization method, to avoid one thread zeroing while another is
reading/writing something to that area) to say if there is a risk.

David Anderson

Arnold Hendriks

unread,
Jan 5, 2002, 5:07:12 PM1/5/02
to
In comp.programming.threads Peter Olcott <olc...@worldnet.att.net> wrote:
>> code that is not guaranteed to be thread-safe on all platforms to gain
>> an optimization (delaying the setting of the NUL-byte).
> What I am thinking is that this hypothetical loss, might
> only be hypothetical, and in actuality there are no
> machines that exist where this would present an actual
> problem. The existence of one machine that does
> have this problem would refute this tentative claim.
You're claiming word tearing never occurs on an actual machine?

David Schwartz

unread,
Jan 5, 2002, 5:28:15 PM1/5/02
to

The problem is that this is an undefined operation. So how can you know
there won't be a problem?

DS

David Schwartz

unread,
Jan 5, 2002, 5:27:39 PM1/5/02
to
Peter Olcott wrote:

> I can't possibly do this because my code is a platform
> independent thus completely portable version of std::string.
> I implemented a fastest possible subset of the functionality
> of std::string, and this must be written to be completely
> platform independent, as the only means of distribution
> is C++ source code, and this code must run unmodified
> across every possible platform. every locking mechanism
> is completely platform specific, thus breaks my design
> requirements.

If you want to write platform-specific thread-safe code, you have to do
one of two things:

1) Use the pthread_mutex_* functions to protect *all* access to shared
data.

2) Give all the responsibility for thread safety to the user of your
class and don't make it unduly hard.

But if you are writing portable code, you definitely shouldn't have to
care what the hardware might or might not do when you attempt operations
not specified in the C, C++, or pthreads standards.

DS

Peter Olcott

unread,
Jan 5, 2002, 10:15:15 PM1/5/02
to

"Arnold Hendriks" <a.hen...@b-lex.com> wrote in message news:a17teg$i1a$1...@news.btcnet.nl...

> In comp.programming.threads Peter Olcott <olc...@worldnet.att.net> wrote:
> >> code that is not guaranteed to be thread-safe on all platforms to gain
> >> an optimization (delaying the setting of the NUL-byte).
> > What I am thinking is that this hypothetical loss, might
> > only be hypothetical, and in actuality there are no
> > machines that exist where this would present an actual
> > problem. The existence of one machine that does
> > have this problem would refute this tentative claim.

> You're claiming word tearing never occurs on an actual machine?

I am claiming that the specific conditions by which you specified
where word tearing occurs do not occur in the specific situation
that I outlined. I can see where word tearing could occur
with access to different bytes, I understood that part, I see
how that could occur. What I still need to know is whether or
not there could be a problem when the access is ALWAYS
to the exact same byte, and yet even with the exact same
value, even still this value is zero. These conditions do not
match those where you specified that word tearing can occur.


Peter Olcott

unread,
Jan 5, 2002, 10:25:02 PM1/5/02
to

"David Anderson" <david.anderson.no_spam@calixo.i_mean_it.net> wrote in message
news:3C3772BF.1040908@calixo.i_mean_it.net...

> > I don't see what the huballoo is about. If two threads are writing the same
> > value to the same memory location, how can there be a problem, even if the
> > memory write is non-atomic.
>
> The problem is about race conditions. If these threads write a 0 to a
> memory address, that would mean that at some point they write something
> else to that location (so it can later be reset).

I am ONLY concerned with the simultaneous access to this
single specific byte position. Any other simultaneous access,
other than read-only access when no writing is occurring
is the burden of the users.

> Imagine then that one thread tests the memory, finds it empty

This is not going to occur, It does not matter whether it is empty
or not, it is always written to. I am ONLY providing a c_str()
member function for a std:;string like class. I merely want to
avoid appending the null termination byte everywhere, except
where (and when) it is needed.

> (writable), is preempted in favour of the second thread which does the
> same check and happily writes a value that'll be squashed as soon as the
> first thread regains control and writes it's value. You here have a
> problem: each thread believes it has done it's duty by writing to that
> address, but thread 2's data is lost.

The scenario is EXACTLY like this...
One thread writes a null termination byte to a specific memory
location. This may or may not be followed by another thread
or process writing this same null termination byte to this same
exact location. This might occur at the exact same instant
that the other null byte was written, because of the possibility
of more than one physical processor. This is every bit of the
whole scenario. There are no tests. There is no other value
than ASCII null that it written, and it is always written to
the exact same byte location. Not an adjacent byte.
Is there any problem with this exact scenario?
If yes, then exactly what is the problem?

Peter Olcott

unread,
Jan 6, 2002, 12:15:13 AM1/6/02
to

"Jeff Greif" <jgr...@spam-me-not.alumni.princeton.edu> wrote in message
news:ZlKZ7.82736$WK1.20...@typhoon.we.rr.com...

> Because it's the wrong question. Two simultaneously executing calls to
> c_str are a much more benign case than many other kinds of contention.
> One thread could write the null byte for c_str, while another one could
> write 5 more bytes starting at the null byte.

No, I can guarantee that this will never occur. The worst possible
case is one physical processor writes a null termination byte, and
at this same instant another physical processor is writing another
null termination byte to exactly this same location. All other scenarios
are not possible.

I know that they are not possible, because they are defined as
not possible in the formal specification. If they do arise, then
they are utterly not my problem. I am seeking to exactly match
the SGI STL thread safety guarantee. Within this guarantee
all these alternative scenarios are defined to not exist.

Peter Olcott

unread,
Jan 6, 2002, 12:25:22 AM1/6/02
to
> But if you are writing portable code, you definitely shouldn't have to
> care what the hardware might or might not do when you attempt operations
> not specified in the C, C++, or pthreads standards.

I want to precisely match the guarantee mentioned below.
This can be done, and is done in a completely platform
independent, C++ source code only way.

The SGI implementation of STL is thread-safe only in the sense that simultaneous accesses to
distinct containers are safe, and simultaneous read accesses to to shared containers are safe. If
multiple threads access a single container, and at least one thread may potentially write, then the
user is responsible for ensuring mutual exclusion between the threads during the container accesses.


David Schwartz

unread,
Jan 6, 2002, 12:33:00 AM1/6/02
to
Peter Olcott wrote:

> > But if you are writing portable code, you definitely shouldn't have to
> > care what the hardware might or might not do when you attempt operations
> > not specified in the C, C++, or pthreads standards.

> I want to precisely match the guarantee mentioned below.
> This can be done, and is done in a completely platform
> independent, C++ source code only way.

Impossible. You have to know too much about the threading model and
memory models involved. C++ simply doesn't provide you the tools to do
this, sorry.

DS

Peter Olcott

unread,
Jan 6, 2002, 2:04:39 AM1/6/02
to

"David Schwartz" <dav...@webmaster.com> wrote in message news:3C37E18C...@webmaster.com...

A bunch of experts have disagreed with you on this
point from the C++ groups. They pointed me to
this group to get deeper support.


David Schwartz

unread,
Jan 6, 2002, 2:27:17 AM1/6/02
to
Peter Olcott wrote:

> > Impossible. You have to know too much about the threading model and
> > memory models involved. C++ simply doesn't provide you the tools to do
> > this, sorry.

> A bunch of experts have disagreed with you on this
> point from the C++ groups. They pointed me to
> this group to get deeper support.

I'd love to see their reasoning. C++ doesn't provide you any way of
knowing what kind of memory visibility you're going to get. It has no
notion of threading. Even if you assume POSIX, POSIX's memory visibility
rules make no distinction between reading and writing, so there's no way
you can assure that concurrent reads are safe.

DS

Ian Lazarus

unread,
Jan 6, 2002, 6:04:55 PM1/6/02
to
If you haven't done so already, you can always test. Write a small program
to exercise the code in question and let 'er rip.


Chris Smith

unread,
Jan 6, 2002, 9:13:24 PM1/6/02
to
Ian Lazarus wrote ...

> If you haven't done so already, you can always test. Write a small program
> to exercise the code in question and let 'er rip.

Unfortunately, this is a horribly bad way to try to resolve thread-safety
issues. The whole point is that the result may be indeterminate... that
means that a problem may lie hidden until the application is in
production, and then arise at the worst possible moment, no matter how
much testing is done.

The only way to determine the thread-safety of a piece of code is to
compare it with a set of guarantees made by a standard of some kind, and
determine if it's guaranteed by that standard to behave correctly. If
so, and if the standard is properly implemented by the platform, then the
code is thread-safe.

As has already been said, use of the given FastString class without
locking would not be correct by the POSIX standard. There may be other
less widely known threading standards by which it is correct. In a
degenerate case, a complete description of a hardware architecture can be
taken as a standard of behavior, but such a hardware architecture was not
given. As such, I wouldn't reasonably call the code thread-safe by any
measuring stick.

Chris Smith

Alexander Terekhov

unread,
Jan 7, 2002, 4:05:24 AM1/7/02
to

David Schwartz wrote:
[...]

> Even if you assume POSIX, POSIX's memory visibility
> rules make no distinction between reading and writing,

Hugh? POSIX memory visibility rules are defined in terms
of *read* and *modify* ("write" falls into it, right ;)
memory "locations" (mem.loc term is undefined, however).

> so there's no way
> you can assure that concurrent reads are safe.

Hugh? It is explicitly stated by the POSIX memory
visibility/synchronization rules (4.10) that:

"Applications may allow more than one thread of control
to read a memory location simultaneously."

Hmm... perhaps you mean that there is no distinction
wrt "safety" of reading and/or writing in the presence
of another thread that may be modifying/writing the
same memory location... yeah, such access is restricted:

"Applications shall ensure that access to any memory
location by more than one thread of control (threads
or processes) is restricted such that no thread of
control can read or modify a memory location while
another thread of control may be modifying it. Such
access is restricted using functions that synchronize
thread execution and also synchronize memory with
respect to other threads."

as for "thread-safety", POSIX defines it as:

"3.313 Reentrant Function

A function whose effect, when called by two
or more threads, is guaranteed to be as if
the threads each executed the function one
after another in an undefined order, even if
the actual execution is interleaved."

"3.396 Thread-Safe

A function that may be safely invoked concurrently
by multiple threads. Each function defined in the
System Interfaces volume of IEEE Std 1003.1-2001
is thread-safe unless explicitly stated otherwise.
Examples are any "pure" function, a function which
holds a mutex locked while it is accessing static
storage, or objects shared among threads."

So to me, for example, something along the lines of
POSIX <string.h> interface IS thread-safe (except
things such as strerror() and strtok(); there is
better _r() functions anyway), BUT it is in MY APPL.
responsibility to ensure proper memory synchronization
(visibility) wrt my shared string objects AND atomicity
of updates of whatever "higher level" shared objects
invariants maintained by my application.

regards,
alexander.

Arnold Hendriks

unread,
Jan 7, 2002, 5:22:16 AM1/7/02
to
In comp.programming.threads Alexander Terekhov <tere...@web.de> wrote:

> "Applications shall ensure that access to any memory
> location by more than one thread of control (threads
> or processes) is restricted such that no thread of
> control can read or modify a memory location while
> another thread of control may be modifying it. Such
> access is restricted using functions that synchronize
> thread execution and also synchronize memory with
> respect to other threads."

Ah. Well, that should basically rule out Peter's trick to store the NUL-byte
in a const member function, as the SGI thread-safety spec seems to allow
calling const functions by multiple readers simultaneously, as long as
they are isolated from writers.

David Schwartz

unread,
Jan 7, 2002, 5:55:26 AM1/7/02
to

You are correct and I am wrong. If the OP can assume POSIX, he can meet
this requirements.

DS

Chris Smith

unread,
Jan 7, 2002, 11:34:26 AM1/7/02
to
David Schwartz wrote ...

> You are correct and I am wrong. If the OP can assume POSIX, he can meet
> this requirements.

I still, however, think that multiple simultaneous writes, even of the
same data, cannot happen without locking and provide a correct
implementation according to POSIX. That's my interpretation anyway. I
see nowhere that "the same data" is distinguished from any other case.

Chris Smith

Alexander Terekhov

unread,
Jan 7, 2002, 3:47:17 PM1/7/02
to

Chris Smith wrote:
[...]

> I see nowhere that "the same data" is distinguished from any other case.

It is not. Invocations of Peter's "const char
*FastString::c_str() const" function (as currently
implemented) just need to be synchronized for shared
"FastStrings" objects in the same way as e.g. his
"FastString& FastString::operator=(char Byte)"
function. Whether physical "object"-modify nature
of c_str() *const* member function is convenient/
"right" or not is another question ;-)

To me, both functions are thread-safe which does
not necessarily mean that you are free to use them
without synchronization on top of thread-safe
interface - *you* should add synchronization for
*your* shared "FastString" objects (if any) on
some level of abstraction/sharing appropriate to
*your* program logic/invariants), IMHO.

regards,
alexander.

Peter Olcott

unread,
Jan 7, 2002, 5:03:13 PM1/7/02
to
> I still, however, think that multiple simultaneous writes, even of the
> same data, cannot happen without locking and provide a correct
> implementation according to POSIX. That's my interpretation anyway. I
> see nowhere that "the same data" is distinguished from any other case.

It would be crucially important that a data time such as
inventory on hand was locked every time before it was
updated. If some sort of locking mechanism was not
provided, then it would be possible for the values to
become incorrectly updated between the read operation,
and the modify operation.

The Classical Example of Memory Writing whereby
locking mechanisms are required for correct updates.
----------------------------------------------------
Process B (or thread) reads InventoryCount of 50.
Process A (or thread) reads InventoryCount of 50.
Process B (or thread) writes the updated value of 40
after subtracting 10 units sold.
Process A (or thread) writes the updated value of 45,
after subtracting 5 units sold.
InventoryCount now holds 45, when it should be 35.

This is the whole purpose of locks, to prevent this scenario.
What I have is a completely different scenario.

(1) Process A writes the value 0 to a specific byte address.

(2) Process B writes the value 0 to this exact same specific byte address.

(3) Process A already having begun its synchronized read operation,
now encounters this 0 value upon its printf() output of the string.

(4) Process B already having begun its synchronized read operation,
now encounters this 0 value upon its printf() output of the string.

There is not at all the same problem as there is in the classic
case of memory writing requiring locking mechanisms.


Chris Smith

unread,
Jan 7, 2002, 6:19:41 PM1/7/02
to
Alexander Terekhov wrote ...

> It is not. Invocations of Peter's "const char
> *FastString::c_str() const" function (as currently
> implemented) just need to be synchronized for shared
> "FastStrings" objects in the same way as e.g. his
> "FastString& FastString::operator=(char Byte)"
> function. Whether physical "object"-modify nature
> of c_str() *const* member function is convenient/
> "right" or not is another question ;-)
>
> To me, both functions are thread-safe which does
> not necessarily mean that you are free to use them
> without synchronization on top of thread-safe
> interface

It is clear, though, that Peter wishes to be able to avoid locking when
c_str is called by multiple threads. Because of a physical write
operation, this is not deterministic under POSIX. That, I think, is the
answer to something that closely approximates Peter's question. His
actual question, which is whether this would break on existing platforms,
would require that he either specify a set of platforms to check on, or
invest an enormous amount of effort researching every existing platform
to verify correctness.

Chris Smith

Peter Olcott

unread,
Jan 7, 2002, 8:37:47 PM1/7/02
to
> It is clear, though, that Peter wishes to be able to avoid locking when
> c_str is called by multiple threads. Because of a physical write
> operation, this is not deterministic under POSIX. That, I think, is the
> answer to something that closely approximates Peter's question. His
> actual question, which is whether this would break on existing platforms,
> would require that he either specify a set of platforms to check on, or
> invest an enormous amount of effort researching every existing platform
> to verify correctness.
>
> Chris Smith

What I am thinking is that any chip designer would
know this off the top of their head. Threads programmers
must often deal with many additional layers on top of this.


Peter Olcott

unread,
Jan 7, 2002, 10:35:33 PM1/7/02
to

"David Schwartz" <dav...@webmaster.com> wrote in message news:3C397E9E...@webmaster.com...

>
> You are correct and I am wrong. If the OP can assume POSIX, he can meet
> this requirements.
>
> DS

The problem is that I can only assume C++.
What is the best thread safety that can be
derived independently of the OS and the hardware?

Peter Olcott

unread,
Jan 7, 2002, 10:36:59 PM1/7/02
to
> > "Applications shall ensure that access to any memory
> > location by more than one thread of control (threads
> > or processes) is restricted such that no thread of
> > control can read or modify a memory location while
> > another thread of control may be modifying it. Such
> > access is restricted using functions that synchronize
> > thread execution and also synchronize memory with
> > respect to other threads."
> Ah. Well, that should basically rule out Peter's trick to store the NUL-byte
> in a const member function, as the SGI thread-safety spec seems to allow
> calling const functions by multiple readers simultaneously, as long as
> they are isolated from writers.
>
>
> --
Yet I still must write this null byte, possibly concurrently.


Peter Olcott

unread,
Jan 7, 2002, 10:42:07 PM1/7/02
to
> As has already been said, use of the given FastString class without
> locking would not be correct by the POSIX standard. There may be other
> less widely known threading standards by which it is correct. In a
> degenerate case, a complete description of a hardware architecture can be
> taken as a standard of behavior, but such a hardware architecture was not
> given. As such, I wouldn't reasonably call the code thread-safe by any
> measuring stick.
>
> Chris Smith
>
Now I see the problem there are multiple official definitions.
My problem is that I must remain platform independent,
and threads are only defined as platform specific. This
means that the definition of thread safety that I must use
must be much weaker.


Alexander Terekhov

unread,
Jan 8, 2002, 3:14:20 AM1/8/02
to

Peter Olcott wrote:
[...]

> What I have is a completely different scenario.
>
> (1) Process A writes the value 0 to a specific byte address.
>
> (2) Process B writes the value 0 to this exact same specific byte address.
>
> (3) Process A already having begun its synchronized read operation,
> now encounters this 0 value upon its printf() output of the string.
>
> (4) Process B already having begun its synchronized read operation,
> now encounters this 0 value upon its printf() output of the string.

If you expect that "Process A"/"Process B" should be
synchronized for *read* operations than they should
NOT *write* anything to shared object(s) protected by
some sync.object they supposed to use for synchronization
(e.g. a read-write lock). For example, I could imagine a
read-write lock implementation that does NOT necessarily
inject a "write memory barrier" reordering constraint
on "rdunlock" operation... this could result in a race-
condition wrt write(s) initiated by "Process A"/
"Process B" and some legitimate writer ("wrlocker")
that could get write access after "Process A"/"Process B"
"rdunlock" and would call e.g. your "FastString&
FastString::operator=(char Byte)" function.

You might want to have a look at:

http://www.primenet.com/~jakubik/mpsafe/MultiprocessorSafe.pdf

regards,
alexander.

Peter Olcott

unread,
Jan 8, 2002, 1:10:28 PM1/8/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message news:3C3AAA5C...@web.de...

I don't follow any of your terminology. It seems that
ALL of your terminology is platform dependent. I MUST
remain utterly platform independent. I am looking for
a way to provide the standard libraries in C++ source
code, that is 100% portable. I think that my question
might be a hardware question, rather than an operating
system software question.

Both of these processes must read the null termination
byte ONLY AFTER they write it. There would NEVER be
any process that would EVER need to read and then write.
Thus am thinking that these READS and WRITES should
remain perfectly synchronized, without any locking
mechanisms at all.

The ONLY problem that I can see is if the hardware itself
screws up and writes something other than ASCII Zero,
when two or more processes are BOTH attempting to write
ASCII Zero at the same time. If this latter scenario could
NEVER occur, then no problem could ever occur with
the thread safety of this code.

David Schwartz

unread,
Jan 8, 2002, 4:01:25 PM1/8/02
to
Peter Olcott wrote:

> "David Schwartz" <dav...@webmaster.com> wrote in message news:3C397E9E...@webmaster.com...

> > You are correct and I am wrong. If the OP can assume POSIX, he can meet
> > this requirements.

> The problem is that I can only assume C++.


> What is the best thread safety that can be
> derived independently of the OS and the hardware?

None, since C++ doesn't know what a thread is.

DS

Peter Olcott

unread,
Jan 8, 2002, 8:37:00 PM1/8/02
to
> > The problem is that I can only assume C++.
> > What is the best thread safety that can be
> > derived independently of the OS and the hardware?
>
> None, since C++ doesn't know what a thread is.
>
> DS

It a compute circuit question do you know any
computer circuit design groups?


Johan Bezem

unread,
Jan 9, 2002, 6:57:31 AM1/9/02
to
Peter Olcott wrote:
> It a compute circuit question do you know any
> computer circuit design groups?

This has got nothing to do with circuit design. Any reasonable multi-processor
design has guards against time-parallel access to the memory bus, in some way.
If the location of the byte is always the same, and both try to write a binary
zero, it doesn't matter who comes first. Such problems only arise when a
read-modify-write cycle is performed, and the write may contain different
values depending on something (be it the 'previous' value, or the random noise
generated by Jupiter...).

IMHO the only issue here is memory granularity: If you need to be rigorously
processor-independent, you may assume at least one processor to write in
chunks of 2/4/8 bytes, so your writing a binary zero becomes a
read-modify-write, changing your single byte to zero, leaving the other bytes
untouched.
If someone else modifies one/more of the other bytes between your read and
write, his changes get undone by your write. This problem cannot be solved
generally without synchronization, only if you're willing to assume a certain
processor architecture; but then, you don't want to be processor-dependent.
This can already be a problem on a single-processor machine with preemptive
multitasking/threading.

HTH,

--
Johan Bezem "Logic is far too lacking in ambivalence.
CSK Software AG That's why it isn't much use in conflict
resolution, or processes in general." -
-- Jostein Gaarder 'Maya'

Alexander Terekhov

unread,
Jan 9, 2002, 10:22:30 AM1/9/02
to

Peter Olcott wrote:
[...]

> The ONLY problem that I can see is if the hardware itself
> screws up and writes something other than ASCII Zero,
> when two or more processes are BOTH attempting to write
> ASCII Zero at the same time. If this latter scenario could
> NEVER occur, then no problem could ever occur with
> the thread safety of this code.

Even if you think that your single non-synchronized
modify/write operation (which you seem to consider
as an "ok" thing to do in SHARED-READ mode) is likely
to be performed atomically on its own (that is, once
started, hardware would guarantee that the operation
will be completed before anyone else is allowed access
to the memory location), without using memory coherency
protocol which is generally/portably provided by MUTEX
kind of synchronization, you will just end up with
corrupted shared data chaos if you allow non-synchronized
writes to your shared data on multiprocessors with weakly
ordered memory (as soon as some thread will be granted
legitimate WRITE access to modify shared "FastString"
object, for example).

POSIX does explicitly PROHIBIT any non-synchronized
modifications/writes to a memory location and it
does not really matter whether your write will be
performed atomically or not. Just accept that you
MUST synchronize unless your data is private or
when your threads just read shared data and it
is 100% guaranteed that no other thread may be
modifying it.

regards,
alexander.

0 new messages