D
D
Damir2014-01-28 08:25:51
C++ / C#
Damir, 2014-01-28 08:25:51

Why can't I synchronize an async method?

Good day to all!
I have the following task. It is necessary to give change in coins to the user through the issuing devices. The problem is that devices can blunt and not give out the full amount. To do this, I planned to use the following algorithm:
1) issue a command to issue N coins
2) receive an asynchronous response about the issue of N coins (there is a corresponding callback #1) or receive an error message with a code and text (already another callback #2);
3) request the total number of issued coins (here he (the hopper) cannot lie) and writes how much he issued - M. The result also comes asynchronously to the corresponding callback #3. Need to wait for a response.
4) Compare M and N, if not equal, go to step 1, but replacing N with NM, if equal, go to the next hopper or to the screen with the result.
So, the crux of the problem.
My COHopper class has the following method:

internal bool DispenseCoins(int numberOfCoins)
        {
            if (!IsInited) return false;
            var methodName = MethodBase.GetCurrentMethod().Name;
            Logger.Fatal("Вызван {0} c параметром numberOfCoins={1}", methodName, numberOfCoins);
            try
            {
                var loop = true;
                var coinsCount = numberOfCoins;
                if(coinsCount==0)return true;
                while (loop)
                {
                    if (DispenseCoinsWithCount(coinsCount))
                    {
                        Logger.Trace("Перед SendDispenseCoinsSendDispenseCoins");
                        while (SendDispenseCoins)
                        {
                            Thread.Sleep(100);
                        }
                        Logger.Trace("После coinsToGivePair.Key.SendDispenseCoins");
                    }
                    else Logger.Trace("DispenseCoinsWithCount - {0}", "False");
                    if (GetInfoAboutAllCountOfCoins())
                    {
                        Logger.Trace("Перед SendDispenseAllCoins");
                        while (SendDispenseAllCoins)
                        {
                            Thread.Sleep(100);
                        }
                        Logger.Trace("После SendDispenseAllCoins");
                    }
                    else Logger.Trace("GetInfoAboutAllCountOfCoins - {0}", "False");
                    if (LastCoinsDeliveryInfo == numberOfCoins)
                        loop = false;
                    coinsCount = numberOfCoins - LastCoinsDeliveryInfo;
                }
                return true;
            }
            catch (Exception e)
            {
                Logger.Fatal("{0} - {1}:{2}", methodName, MessageResource.ErrorUnExpectedException, e.Message);
                return false;
            }
        }

Where the SendDispenseAllCoins and SendDispenseCoins flags are changed in the corresponding callbacks:
SendDispenseCoins - either when a message about a successful issue is received in callback #1, or when an error message is received in callback #2
SendDispenseAllCoins - when a message is received in callback #3
As a result, a loop occurs on first while. Though messages come and meanings change.
I think that this way of waiting for messages is a bit blunt. Maybe someone has experience of writing similar things, I would be grateful if you share. Or tell me how to fix this implementation.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
P
Pavel Osadchuk, 2014-01-28
@YaMirok

If we are talking about multithreading, use synchronization objects (for example, ManualResetEvent) to synchronize threads. Then there is no need to fence this whole idea with callbacks
and this miserable code

while (SendDispenseAllCoins)
{
    Thread.Sleep(100);
}

can be replaced with 1 line, for example this
This is in the case of manually creating threads.
But if you have .net 4.5, I recommend not to manually create threads, but to use the "Task-based Asynchronous Pattern" (TAP), namely the async-await and Task constructs

R
Ruslan Lopatin, 2014-01-28
@lorus

Replace

if (LastCoinsDeliveryInfo == numberOfCoins)
     loop = false;
coinsCount = numberOfCoins - LastCoinsDeliveryInfo;

on the
if (LastCoinsDeliveryInfo == coinsCount)
     loop = false;
coinsCount -= LastCoinsDeliveryInfo;

For I suspect that it LastCoinsDeliveryInfocontains only the number of coins issued last.
But in general, this is not how asynchronous code is written. Thread.Sleep is some kind of kindergarten. Better use Future/Promise, or wait/notify, whatever C# has. SendDispenseCoinsIn addition to being inefficient , changing fields asynchronously SendDispenseAllCoinsmay not work: the main thread may simply not see the changes made by another thread.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question