Ian, I think MS dug their own hole when they added the Seek() method to
Stream that allows use of a signed offset and anything other than
SeekOrigin.Current.

Adding a method to asynchronously write and seek in one function adds
nothing to the interface that Stream currently provides.  The fact that
this fictional function may provide a concurrent-friendly (or "atomic")
implementation is just that: an implementation detail.  Conversely, the
fact that calling Seek() then BeginWrite() is not concurrent-friendly is
also an implementation detail; but implied in the point that Stream is
documented as not thread-safe.

I would argue with the original post that a new method is required to make
Stream (or FileStream in that context) thread-safe.

I think the current Stream.Seek() is a pollution of a stream abstraction
that has been kludged with the likes of CanSeek().

On Sat, 17 Dec 2005 14:00:57 -0000, Ian Griffiths <[EMAIL PROTECTED]>
wrote:

>It seems to me that there's a clear difference between what Seek gives
>you and what you're asking for. (Otherwise you wouldn't be asking for
>it.) I admit that I chose poor terminology to describe the feature: I
>should have said "concurrent random access" rather than just "random
>access". But I stand by my assertion that it shouldn't be in Stream.
>
>The problem I have with adding this to the Stream abstraction is that
>all of a sudden, *every* Stream has to support it.
>
>So you undoubtedly *could* have something not dissimilar to Stream that
>support concurrent random access. But if you made this a feature of
>Stream you just made it mandatory for every implementation of Stream to
>support this.
>
>That makes it a non-starter for where we are today - this suggestion
>will never fly because Stream shipped almost 4 years ago, and there's no
>way to go and add this functionality retrospectively to all the Streams
>everyone has implemented ever since.
>
>Given where we are, the only way to add this functionality would be to
>introduce a new more specialized abstraction. (Either specifically to
>files, or possibly as some new AsyncStream abstraction.)
>
>So this leaves this discussion as an academic question: should Stream
>have had this functionality from the start?
>
>I think Stream's better without this, because this extra feature would
>increase the cost of implementing Stream.  And this is the tradeoff you
>often get with abstractions: making them rich enough to be useful but
>simple enough that anyone can be bothered to implement them.
>
>Mandating that all streams that support seeking also support concurrent
>random access seems like a high tax to impose on implementing Stream.
>
>If everyone were clamouring for it, then it'd be reasonable.  But
>they're not.  I've worked on a wide range of .NET projects in the years
>since .NET shipped, and while I can appreciate in abstract that this
>would be a nice feature, I've never run into a scenario where this would
>have been useful in practice. (But I have run into scenarios where I
>wanted to implement Stream. So this feature would have been a net loss
>for me.)
>
>More tellingly, you rarely see anyone asking for it on public forums. As
>far as I can tell from the various mailing lists, newsgroups, and forums
>I've hung out on, my experience of never having come across a concrete
>need for this is more common than your experience.
>
>Which suggests that Microsoft made the right decision: Stream would have
>been the wrong place to put support for concurrent random access.
>
>So even if you were starting from a clean slate, and wanted v1.0 of the
>framework to offer this functionality (and I agree it would be nice to
>have, despite the fact that I've never actually needed it) I still think
>it would be a mistake to put something this specialized into something
>as generic as Stream.
>
>It's at best a poor match (and at worst, inappropriate) for most
>implementations of Stream. For the implementations of Stream for which
>it's appropriate, it's not useful most of the time.
>
>To steal a phrase that Ron Jeffries recently used on the TDD mailing
>list:
>
>  " it would be a bit like having a #10 Torx driver as part
>    of my hammer. Occasionally useful but also an odd addition."
>
>
>Of course it's hugely frustrating if you happen to hit the case where
>you want to do something that you know would be pretty easy for the
>underlying implementation you happen to be using. But that doesn't
>translate into an argument that Stream is designed wrong.
>
>
>--
>Ian Griffiths
>http://www.interact-sw.co.uk/iangblog/
>
>> -----Original Message-----
>> From: John Davis
>>
>> Yes, I disagree with your assertion stating the Stream interface is
>the
>> wrong abstraction for random access because it already contains a Seek
>> method.  The random access is already there.
>>
>> So, for streams where (CanSeek == true) there should also be a
>> BeginRead/Write(file_offset, ...) which is threadsafe.
>>
>> Yes, you're right the docs say it isn't threadsafe.  But for heaven
>sake,
>> surely we can add a class that is threadsafe for file io in the same
>way
>> the
>> Win32 API provides.  How are people supposed to write high throughput
>> server
>> software without a good async managed file io class?  Apparently
>everyone
>> is
>> still using C++.
>>
>> As you may have guessed, I've already hit this on my current project.
>> Lots
>> of locks to compensate for the above oversight.
>>
>> >From: Ian Griffiths <[EMAIL PROTECTED]>
>> >Reply-To: "Discussion of advanced .NET topics."
>> ><[email protected]>
>> >To: [email protected]
>> >Subject: Re: [ADVANCED-DOTNET] Possible defect in BeginWrite on
>> FileStream
>> >Date: Thu, 15 Dec 2005 22:42:36 -0000
>> >
>> >John Davis wrote:
>> > > Ian I'm afraid you're really mistaken on this one.
>> >
>> >Which bit do you disagree with?
>> >
>> >Do you disagree that Stream is the wrong abstraction for random
>access?
>> >
>> >Do you disagree that if a class is documented as not safe for
>> >multi-threaded access, then it doesn't really matter what new methods
>> >you add, you still can't use it from multiple threads?
>> >
>> >Do you disagree with the claim that Stream offering stream-like
>> >behaviour is a design limitation and not an actual defect? (The
>absence
>> >of a random access API might be regarded as a defect, but that
>doesn't
>> >mean there's necessarily a problem with the stream API - it does what
>> >it's designed to do.)
>> >
>> >You've obviously thought long and hard about it - almost 7 months
>> >according to the email timestamps. :)  But I can't tell what I said
>that
>> >you think I'm "really mistaken on".
>> >
>> >I'm not disagreeing that random access (as opposed to stream-like
>> >access) would be nice to have. (Although it's not something I happen
>to
>> >have run into a need for in any .NET projects yet.) I'm just saying
>> >Stream's the wrong place for it.
>> >
>> >In particular, bear in mind that not all Streams are implemented on
>top
>> >of something that necessarily has intrinsic OVERLAPPED-like
>> >functionality. (Not all streams are files or file-like handles.)
>> >
>> >
>> >
>> > > What I'm looking for is the equivalent of a ReadFile or WriteFile
>> > > call here the offset is passed in the OVERLAPPED struct.
>> >
>> >I agree there are circumstances in which this would be handy. But I
>> >stand by my assertions that Stream is the wrong abstraction for this.
>> >Not every Stream is a file. Stream is not meant to be an abstract
>> >representation of a file - it's more widely applicable than that.
>(Hence
>> >its narrower API - the more specific an API an abstraction has, the
>less
>> >broadly applicable it is.)
>> >
>> >
>> > > The call can occur through overlapped IO, or an IO completion
>> > > port.  The call is also atomic.
>> >
>> >And it's not presenting a stream-like abstraction.  I think that's at
>> >the heart of the issue.
>> >
>> >
>> >
>> > > There needs to be a random access async read/write of some
>> > > sort which uses the OVERLAPPED struct in the Win32 API in that
>> > > it has a file offset field for the read or write.
>> >
>> >Sure, just probably not Stream.
>> >
>> >I guess if you changed nature of the Stream API by adding new
>> >non-streamish functionality and also changed the classes so they
>> >permitted concurrent access then that'd solve the problem. (Except
>for
>> >the fact that this might break a lot of existing streams because they
>> >don't implement this feature right now...)
>> >
>> >But aren't you introducing a whole new abstraction?
>> >
>> >
>> > > If one observes the current implementation in
>> > > DotNetReflector, the OVERLAPPED struct is getting populated
>> > > via the FileStream Seek call.  The OVERLAPPED struct is then
>> > > used on the next async write.  Why implement it this way if
>> > > FileStreams can only be used by a single thread?
>> >
>> >Err...isn't that a distinctly sequential approach to the problem? It
>> >presumes that the call to Seek and the async write will follow on one
>> >after the other without interference.
>> >
>> >You'd need a completely different implementation if you wanted to
>> >support non-sequential use wouldn't you?
>> >
>> >
>> >--
>> >Ian Griffiths
>> >
>> >
>> >On Thu, 26 May 2005 23:22:45 +0100, Ian Griffiths
>> ><[EMAIL PROTECTED]>
>> >wrote:
>> >
>> > >Even if there were an atomic method how would that help?  It
>wouldn't
>> > >eliminate the race condition, because it would still be illegal to
>call
>> > >the method simultaneously on multiple threads. (FileStream's
>> > >documentation says it's illegal to do that.)  So you'd still need
>to
>> >use
>> > >locking or some other synchronization method to make sure your
>threads
>> > >take it in turns even if there were an atomic method.
>> > >
>> > >I agree it would be cleaner to have a random access method if
>random
>> > >access is what you're doing - a stream isn't really the right
>> > >abstraction in that case.  (Sadly it's the only one we're offered
>> > >AFAIK.)
>> > >
>> > >But is this a defect?  It's a bug to use a stream from multiple
>threads
>> > >without synchronization.  It would still be a bug even with the
>atomic
>> > >method you propose.
>> > >
>> > >
>> > >--
>> > >Ian Griffiths
>> > >http://www.interact-sw.co.uk/iangblog/
>> > >
>> > >> -----Original Message-----
>> > >> From: John Davis
>> > >>
>> > >> >Are you saying that locking, Seeking, BeginWriteing, and
>unlocking
>> >is
>> > >> not good enough?
>> > >>
>> > >> Well, I guess it is good enough, just doesn't seem very elegant.
>> > >Would be
>> > >> nice if there was an offset in there so one "atomic" call could
>be
>> > >made.
>> > >> Same as with Win32 overlapped io.
>> > >>
>> > >> >Does the BeginWrite not in effect take a snapshot of
>> > >> the seek location when the operation starts?
>> > >>
>> > >> I don't know for certain if it does, I certainly hope so.  Time
>to go
>> > >> digging with reflector I guess.
>> > >>
>> > >> Ian Griffiths <[EMAIL PROTECTED]> wrote:
>> > >> The documentation says that members of this class are not thread
>> >safe,
>> > >> so multiple threads shouldn't be using this at any given
>instance.
>> >You
>> > >> need to do some kind of locking if you have multiple threads
>using
>> >it.
>> > >>
>> > >> Are you saying that locking, Seeking, BeginWriteing, and
>unlocking is
>> > >> not good enough? Does the BeginWrite not in effect take a
>snapshot of
>> > >> the seek location when the operation starts?
>> >
>> >===================================
>> >This list is hosted by DevelopMentor(r)  http://www.develop.com
>> >
>> >View archives and manage your subscription(s) at
>> http://discuss.develop.com
>>
>> ===================================
>> This list is hosted by DevelopMentor(r)  http://www.develop.com
>>
>> View archives and manage your subscription(s) at
>> http://discuss.develop.com
>
>===================================
>This list is hosted by DevelopMentorĀ®  http://www.develop.com
>
>View archives and manage your subscription(s) at
http://discuss.develop.com

===================================
This list is hosted by DevelopMentorĀ®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to