On Tuesday 19 July 2005 17:00, Jeff Hill wrote:
> > From: Andrew Johnson [mailto:[email protected]]
> > The main thing that bothers me is your StreamPosition interface.
> > The position() and movePosition() methods implies that every
> > StringSegment includes an iterator into the string, which I assume
> > is used by the StreamRead and StreamWrite methods to indicate where
> > their next access will occur.
> > It's only possible to have one such iterator per
> > StringSegment, so it's not possible for two threads to access the
> > same string simultaneously, even if they're both only reading from
> > it.
>
> Therefore two conclusions:
>
> 1) Two threads must not have read or write access to the same string
> simultaneously, and therefore some sort of mutex locking is required
> - nothing new here.
AFAICS, there is no need to pack the streamRead interface into the class
that represents the string itself. Instead, a streamRead object should
be created from an existing string whenever read access to the string
is needed. Thus, each thread uses its very own (stack allocated)
streamRead object. A streamRead object is more or less a read iterator
over a string. It will contain some additional methods from the
streamPosition interface (like position and movePosition). It should
not be passed around (and there is no need to).
What for write locks? Not necessary, either. We simply don't give write
access to (already constructed) strings. Think about it: do you know
any example where you actually need to destructively update a string,
once you have it constructed?
There may be code examples where such update is done as a low-level
optimization. That is, you overwrite an existing string instead of
first throwing it away, and then creating a new one. Apart from being
dangerous, I doubt very much that this kind of optimization is really a
big win, if you take the additional amount of necessary locking and
copying into account.
[One could even experiment with a reference counted string
implementation and find out how the avoidance of copying when passing
strings weighs against the necessary locking of the reference count
updates.]
Most of the time (at least in the IOC, but I believe this is true for
most clients, too) strings are merely copied from one place to another,
or else newly constructed from existing pieces.
For creating a new string, we need some variant of streamWrite object,
but again, this should be a separate object. If construction is done
(possibly after many "write" operations), a new string is constructed
from the streamWrite object, which is then discarded. And again, I
doubt that write access is needed at arbitrary positions. Having the
write position fixed at the end of the string under construction is
general enough for any application I can think of. With such an
invariant, optimizations under the hood can be used to minimize the
amount of copying when creating the new string from the streamWrite
object.
> >From my perspective, one must either include the lock in the class,
> > use
>
> guard classes to guarantee that locking contracts are executed, or
> let codes that use the string class remember what locking is required
> (no compiler enforcement).
Or use non-modifiable strings and forget about locking.
Respectively, for a reference counting scheme, locking is done only when
passing a string or when a string gets destroyed, and then only for an
extremely short period (one integer increment), so it can be drastic
and cheap (e.g. intLock in vxWorks).
> Of course, the StreamPosition / StreamRead / StreamWrite interfaces
> could be passed separately from the rest of the string interface, but
> this would just about eliminate use of strings with templates as
> templates require one entity (template argument) implementing any
> type that gets used. Therefore, some temporary helper objects
> implementing the StreamPosition / StreamRead / StreamWrite interfaces
> might be instantiated on the stack for the duration of the call to
> the CA/DB function reading/writing a string.
Yes, this is the way to go, with the only difference that
o strings can't be modified
o a string can be created from a (temporary) streamWrite object
o a (temporary) streamRead object can be created from a string
[With "temporary" I mean stack allocated, here, not to be confused with
the C++ concept of "temporary object".]
> Another alternative would be to have a function in the core string
> interface that returns a reference to the StreamPosition / StreamRead
> / StreamWrite interfaces, but I decided against adding a method that
> returns an indirect handle to internal storage. Lock management is
> complex with that approach (or at least requires a guard class in the
> interface), and with that approach there is a stronger possibility of
> some user using a StreamPosition / StreamRead / StreamWrite against a
> target object that no longer exists.
Yes.
> Also, if you eliminate StreamPosition / StreamRead / StreamWrite and
> the methods in StringSegment that manipulate the current position
> there isn't much left.
And this is how it should be. The string itself has almost no
properties, but it can be freely passed around as a value.
> > If the V3 IOC used StringSegment instead of char* for storing
> > record names, that would means that as long as a lockset was
> > locked, the CA UDP task would not be able to complete a search
> > where the record name it's looking for is lower down the same hash
> > bucket as a record in that lockset (since the only record-related
> > mutex we have in V3 is in the lockset, so you'd have to take that
> > before you'd be allowed to change the current position of the name
> > string).
> >
> > I don't think that's acceptable, and I doubt that you would either.
> > A string is not an iterator and should not contain one, since it
> > prevents simultaneous access to two different parts of the same
> > string, even from inside the same function.
>
> As mentioned above, the StreamPosition / StreamRead / StreamWrite
> interfaces might need to be temporarily inflated thread private
> state, but nevertheless passed along through the CA and DB interfaces
> that manipulate strings. Therefore, the lock set wouldn't need to be
> locked.
I get very cold feet whenever I hear the word "thread private state".
Don't do that, there are better ways.
> As soon as you have on line addition of records and or changes to
> record names then you certainly will need to lock out the CA UDP
> thread at certain times.
Online add & delete of records will be quite rare, compared to name
lookup.
Ben
- Replies:
- Re: Standard String Kay-Uwe Kasemir
- References:
- FW: Standard String Jeff Hill
- Navigate by Date:
- Prev:
Re: Standard String Kay-Uwe Kasemir
- Next:
Re: Standard String Kay-Uwe Kasemir
- Index:
2002
2003
2004
<2005>
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
FW: Standard String Jeff Hill
- Next:
Re: Standard String Kay-Uwe Kasemir
- Index:
2002
2003
2004
<2005>
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|