StephenCleary / AsyncEx

A helper library for async/await.
MIT License
3.53k stars 356 forks source link

AsyncProducerConsumerQueue exception #12

Closed dksmtgit closed 9 years ago

dksmtgit commented 9 years ago

When adding to an AsyncProducerConsumerQueue a .NET 4.5 application is sometimes getting a "Deque is empty" exception. Tracing through this happens inside AsyncLock when releasing the lock protecting the AsyncProducerConsumerQueue. The exception is generated in the Deque class RemoveFromFront.method.

StephenCleary commented 9 years ago

Can you post a reproducible example?

dksmtgit commented 9 years ago

Here's the application method in question. It's got some issues with bad practices which probably are what is causing the problem.

The ForEach on the Linq Query against async void lambda delegate either causes exceptions due to the Add method calls to non threadsafe list and dictionary objects or it occasionally causes the "Deque is empty" exception when calling the "SendLocalMessage" method which adds a message to an AsyncProducerConsumerQueue object. The method has to be rewritten to not use the lambda and ForEach, my concern was that somehow it was breaking the queue object as well.

    private async Task<bool> TurnOnPickLights()
    {
        // Clear previous bay msg light if it was ManualInduct
        if (_bayNumber > 1)
        {
            var bayWorker = clBayWorkflow.GetBayWorker(_bayNumber - 1);
            if (!bayWorker.IsAutoInduct) await

FFMessageHelper.ClearMsgLight(_bayNumber - 1); }

        _pickLights.Clear();//clear previous

        var taskList = new List<Task>();
        using (var ctx = clGlobal.LocalDb.GetDbContext())
        {
            (from P in ctx.tblPicks
             where P.PickTicketId == _currentBox.BoxID
               && P.LogicalBay == _currentBox.CurrentBay
               && P.QtyPicked < P.QtyToPick
             select P).ToList().ForEach(async pick =>
            {
                //
                await

clBayWorkflow.TransceiverInterface.SendLocalMessage((byte) pick.BayLight, enumMessageFunction.FlashLEDFast, (int) (pick.QtyToPick - pick.QtyPicked));

                // Display/Log this pick

clBayWorkflow.LogMessage(string.Format("@TurnOnPickLights: Box={0} Bay={1} Light={2} Qty={3}", _currentBox.BoxID, _bayNumber, pick.BayLight, pick.QtyToPick));

                var tcs = new TaskCompletionSource<byte>();
                _buttonPushes.Add((byte)pick.BayLight, tcs);
                taskList.Add(tcs.Task);
            });
        }

        if (_buttonPushes.Count > 0)
        {
            // Display box number in msg light
            await FFMessageHelper.WriteBoxToMsgLight(_bayNumber,

FFMessageHelper.GetBoxIdForDisplay(_currentBox.BoxID), false); }

        await Task.WhenAll(taskList);

        var results = await Task.WhenAll(ClearPickLights(),

TurnOnMsgLight()); return results.All(x => x); }

On 2/21/2015 4:41 AM, Stephen Cleary wrote:

Can you post a reproducible example?

— Reply to this email directly or view it on GitHub https://github.com/StephenCleary/AsyncEx/issues/12#issuecomment-75370011.

StephenCleary commented 9 years ago

Do you have a full stack trace? And, if you can, it would help greatly if you can post a repro. By "repro", I mean a short but complete program that duplicates the problem.

StephenCleary commented 9 years ago

Never mind, I found the problem. I'll be releasing a fix shortly.

dksmtgit commented 9 years ago

Thanks, I was just settling down to get a trace.

On 2/21/2015 9:44 AM, Stephen Cleary wrote:

Never mind, I found the problem. I'll be releasing a fix shortly.

— Reply to this email directly or view it on GitHub https://github.com/StephenCleary/AsyncEx/issues/12#issuecomment-75382879.

StephenCleary commented 9 years ago

OK, it should be fixed in the 3.0.1-pre version: https://www.nuget.org/packages/Nito.AsyncEx/3.0.1-pre

Let me know if there's still a problem. This is a race condition that is not easily reproducible with unit tests, so I don't have any verification at this time that the bug is actually... you know... fixed. ;)

dksmtgit commented 9 years ago

Thanks, I have trouble reproducing it too. It seems to occur more frequently when running the app in the debugger in the IDE, if I run the app standalone it is much less frequent.

On 2/21/2015 6:01 PM, Stephen Cleary wrote:

OK, it should be fixed in the 3.0.1-pre version: https://www.nuget.org/packages/Nito.AsyncEx/3.0.1-pre

Let me know if there's still a problem. This is a race condition that is not easily reproducible with unit tests, so I don't have any verification at this time that the bug is actually... you know... fixed. ;)

— Reply to this email directly or view it on GitHub https://github.com/StephenCleary/AsyncEx/issues/12#issuecomment-75414927.

dksmtgit commented 9 years ago

I've done extensive testing for a while now and the problem has not recurred, so I'd say it is fixed.

On 2/21/2015 9:01 PM, Stephen Cleary wrote:

OK, it should be fixed in the 3.0.1-pre version: https://www.nuget.org/packages/Nito.AsyncEx/3.0.1-pre

Let me know if there's still a problem. This is a race condition that is not easily reproducible with unit tests, so I don't have any verification at this time that the bug is actually... you know... fixed. ;)

— Reply to this email directly or view it on GitHub https://github.com/StephenCleary/AsyncEx/issues/12#issuecomment-75414927.