简体   繁体   中英

Understanding await and async in .NET

I am working on refactoring code that uses the Bootstrap protocol to update the firmware of several nodes in a machine. The current code looks something like this (pseudo-code):

public void StartUpdate()
{
    Sokcet bootpSocket = new Socket():
    StateObject bootpState = new StateObject(bootpSocket);

    BOOTPReceive(bootpState);
    SendMagicPacket();

    while (!IsError && !IsUpdateComplete)
    {
        //wait for BOOTP/Update to finish before returning to caller
    }
}

private void BOOTPReceive(object state)
{
    bOOTPSocket.BeginReceive(PACKET_DATA, 0, PACKET_DATA.Length, 0, OnBOOTPReceive, state);
}

SendMagicPacket()
{
    //create and send magic packet
    // this will tell the node to respond with a BOOTPPacket
}

private void OnBOOTPReceive(IAsyncResult result)
{
    StateObject state = (StateObject) result.AsyncState;
    Socket handler = state.workSocket;
    int bytesRcvd = handler.EndReceive(result);
    packet = PACKET_DATA;

    if(isValidBOOTP(packet))
    {
        SendBOOTPResponse();    
    }
    else{
        BOOTPReceive(); //keep listening for valid bootp response
    }
}

private void SendBOOTPResponse()
{
    UdpClient udpClient = new UdpClient();
    udpClient.BeginSend(packetData, packetData.Length, BROADCAST_IP, (int)UdpPort.BOOTP_CLIENT_PORT, OnBOOTPSend, udpClient);
}

private void OnBOOTPSend(IAsyncResult result)
{
    UdpClient udpClient = (UdpClient)result.AsyncState;
    int bytesSent = udpClient.EndSend(result);
    udpClient.Close();
}

What I want to do is convert this to async-await but still require that I don't return back to the caller right away. How would I go about doing this? Is this possible to do? And would this be the right thing to do since await-async propagates all the way to the top?

Pseudo-code of what I think this would look like:

public void StartUpdate()
{
    bool result = await SendMagicPacket();
    bool IsError = await BOOTPCommunication(); //Handles all of the BOOTP recieve/sends
    //don't return to caller until BOOTPCommunication is completed. How do i do this?
}

You need to wait for the two tasks try the following:

public async Task StartUpdate()
    {
        var resultTask =  SendMagicPacket();
        var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends

        await Task.WhenAll(new[]{resultTask, isErrorTask});
        //don't return to caller until BOOTPCommunication is completed. How do i do this?
    }

//wait for BOOTP/Update to finish before returning to caller

You don't need any async IO at all because you want to wait until all operations are done. I assume you have copied some sample code. Most sample code uses async socket APIs.

Switch everything over to synchronous socket APIs and you're done.

If you want to keep this async for some reason you can indeed switch to await and untangle this code. The pseudo-code you posted looks like a good goal. It forces the surrounding method to be async Task , though.

You can deal with that by making all callers recursively async as well. If you don't need to conserve threads you could block on that task and have a mostly synchronous call chain. At that point you lose all async benefits, though.

Radin was on the right track, but I think what you want is something like this:

You need to wait for the two tasks try the following:

public async Task StartUpdate()
{
    var resultTask =  SendMagicPacket();
    var isErrorTask = BOOTPCommunication(); //Handles all of the BOOTP recieve/sends

    Task.WhenAll(new[]{resultTask, isErrorTask}).Wait(); //Wait() will block so that the method doesn't return to the caller until both of the asynchronous tasks complete.
}

What that allows is SendMagicPacket and BOOTPCommunication to both fire simultaneously, but to wait for BOTH to complete. Using that pattern you can fire of N events simultaneously, while using Wait() to wait for all to finish so that the method itself returns synchronously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM