简体   繁体   中英

C# how to use async and await?

I make serial communication method. it return receive message

first, button click

List<string> SendPkt = new List<string>();
List<string> RecvPkt = new List<string>();

private void btnRead_Click(object sender, EventArgs e)
{
    SendPkt.Clear();
    RecvPkt.Clear();

    C_Serial c_serial = new C_Serial();

    Trace.WriteLine("start : "+DateTime.Now);

    RecvPkt = c_serial.CommunicationJob(Port, Baud, SendPkt);

    for (int i = 0; i < RecvPkt.Count; i++)
        Trace.WriteLine(RecvPkt[i]);

    Trace.WriteLine("end : "+DateTime.Now);
}

and C_Serial is...

public List<string> CommunicationJob(string port, int boud, List<string> sendPkt)
{
    string openResult = OpenPort(port, boud);
    string recvMsg = "";
    ....
    List<string> recvs = new List<string>();

    for (int i = 0; i < sendPkt.Count; i++)
    {
        recvMsg = SendAndRecv(sendPkt[i]);
        Trace.WriteLine("recvMsg : " + recvMsg);
        recvs.Add(recvMsg);
    }

    return recvs;
}
...
public string SendAndRecv(string sendPkt)
{
    string recvPkt = "";
    serialWrite(sendPkt);
    recvPkt = waitDataReceived();
    return recvPkt;
}

...

private string waitDataReceived()
{
    while(true)
    {
        // check about message recv complete
    }
}

waitDataReceived() has infinity loop so it must work as thread

So I make SendAndRecv() like that

public string SendAndRecv(string sendPkt)
{
    string recvPkt = "";
    serialWrite(sendPkt);
    Thread th = new Thread(() => recvPkt = waitDataReceived());
    th.Start();
    th.Join();
    return recvPkt;
}

but Join() is block UI when infinity loop.

I search about that and I find async/await.

So I modified SendAndRecv()

public async Task<string> SendAndRecv(string sendPkt)
{
    string recvs = "";
    serialWrite(sendPkt);   
    recvs = await Task.Run(() => waitDataReceived());
    return recvs;
}

And It use in CommunicationJob() like this

recvMsg = SendAndRecv(sendPkt[i]).Result;

But it still blocks the UI. Even if the infinite loop breaks, it is not released.

And don't print recvMsg in CommunicationJob().

Program is stop.

How can I use thread not block UI and wait until return value?

you need to buble up the pattern until your GUI click method. In the line of succession (calling hierarchy) every method has to be async and use await

public async Task<List<string>> CommunicationJob(string port, int boud, List<string> sendPkt)
{
    string openResult = OpenPort(port, boud);
    string recvMsg = "";
    ....
    List<string> recvs = new List<string>();

    for (int i = 0; i < sendPkt.Count; i++)
    {
        recvMsg = await SendAndRecv(sendPkt[i]);
        Trace.WriteLine("recvMsg : " + recvMsg);
        recvs.Add(recvMsg);
    }

    return recvs;
}

private async void btnRead_Click(object sender, EventArgs e)
{
    SendPkt.Clear();
    RecvPkt.Clear();

    C_Serial c_serial = new C_Serial();

    Trace.WriteLine("start : "+DateTime.Now);

    RecvPkt = await c_serial.CommunicationJob(Port, Baud, SendPkt);

    for (int i = 0; i < RecvPkt.Count; i++)
        Trace.WriteLine(RecvPkt[i]);

    Trace.WriteLine("end : "+DateTime.Now);
}

This should ensure that the UI does not freeze.

You could actually write the await directly after the return statement:

public async Task<string> SendAndRecv(string sendPkt)
{
    string recvs = "";
    serialWrite(sendPkt);
    return await Task.Run(() => waitDataReceived());;
}

Not only do you have to make SendAndRecv async, you also have to make all its callers, and the callers of those callers (and so on) async . And when you call an async method, you use await .

Therefore, CommunicationJob should be async

public async Task<List<string>> CommunicationJob(string port, int boud, List<string> sendPkt)
{
    string openResult = OpenPort(port, boud);
    string recvMsg = "";
    ....
    List<string> recvs = new List<string>();

    for (int i = 0; i < sendPkt.Count; i++)
    {
        recvMsg = await SendAndRecv(sendPkt[i]); // <--- note this line!
        Trace.WriteLine("recvMsg : " + recvMsg);
        recvs.Add(recvMsg);
    }

    return recvs;
}

And btnRead_Click should be async

private async void btnRead_Click(object sender, EventArgs e)
{
    SendPkt.Clear();
    RecvPkt.Clear();

    C_Serial c_serial = new C_Serial();

    Trace.WriteLine("start : "+DateTime.Now);

    RecvPkt = await c_serial.CommunicationJob(Port, Baud, SendPkt);

    for (int i = 0; i < RecvPkt.Count; i++)
        Trace.WriteLine(RecvPkt[i]);

    Trace.WriteLine("end : "+DateTime.Now);
}

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