Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Race? #12

Closed
henricj opened this issue Sep 10, 2018 · 5 comments
Closed

Race? #12

henricj opened this issue Sep 10, 2018 · 5 comments

Comments

@henricj
Copy link

henricj commented Sep 10, 2018

We've been seeing intermittent problems with data getting lost and have finally narrowed it down to a simple test case that sometimes fails. It almost always fails on a Threadripper box and perhaps one of three attempts fail on a six year old laptop. Is this code reasonable and, if so, why does it sometimes fail with no data in the MemoryStream?

Trying to wait for the reader to complete doesn't help since it doesn't actually complete.

        [TestMethod]
        public async Task SingleByte()
        {
            var expected = new byte[] { 7 };
            using (var ms = new MemoryStream())
            {
                var pipeWriter = StreamConnection.GetWriter(ms);
                var memory = pipeWriter.GetMemory(expected.Length);
                expected.AsMemory().CopyTo(memory);
                pipeWriter.Advance(expected.Length);
                await pipeWriter.FlushAsync().ConfigureAwait(false);
                pipeWriter.Complete();
                ms.Position = 0;
                var actual = ms.ToArray();
                Assert.IsNotNull(actual);
                CollectionAssert.AreEqual(expected, actual);
            }
        }

        [TestMethod]
        public async Task SingleByteWithWait()
        {
            var expected = new byte[] { 7 };
            using (var ms = new MemoryStream())
            {
                var pipeWriter = StreamConnection.GetWriter(ms);
                var memory = pipeWriter.GetMemory(expected.Length);
                expected.AsMemory().CopyTo(memory);
                pipeWriter.Advance(expected.Length);
                await pipeWriter.FlushAsync().ConfigureAwait(false);
                pipeWriter.Complete();
                var doneTcs = new TaskCompletionSource<bool>();
                pipeWriter.OnReaderCompleted((ex, obj) =>
                {
                    var tcs = (TaskCompletionSource<bool>)obj;
                    if (null != ex) tcs.TrySetException(ex);
                    else tcs.TrySetResult(true);
                }, doneTcs);
                await doneTcs.Task.ConfigureAwait(false);
                ms.Position = 0;
                var actual = ms.ToArray();
                Assert.IsNotNull(actual);
                CollectionAssert.AreEqual(expected, actual);
            }
        }
@mgravell
Copy link
Owner

mgravell commented Sep 10, 2018 via email

@henricj
Copy link
Author

henricj commented Sep 10, 2018

What we wound up doing was to have an extension method on Stream that creates a pipe, does a Task.Run() on a loop that copies from the pipe to the stream until it sees an empty buffer and with IsCompleted true. The pipe's writer is returned and a the created task is provided as an "out" parameter. A value tuple return with both the PipeWriter and a Task might be an alternative, but we couldn't see a clean way to avoid having two separate things to return.

Perhaps if the reader was guaranteed to complete after the last write propagated to the stream and something like the OnReaderCompleted() callback gunk were wrapped in an extension method?

@mgravell
Copy link
Owner

mgravell commented Sep 11, 2018 via email

@XCounterAlex
Copy link

CopyFromWritePipeToStream could call reader.complete() on the way to oblivion. That would follow the whole pipelines thing, and PipeWriter.OnReaderCompleted will do the right thing, even if that is a bit

(i'm new to this GitHub thing) so excuse any lack of Etiquette)

@mgravell
Copy link
Owner

It will do in the next build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants