我做串行通讯方法。它返回接收消息
首先,点击按钮
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);
}
C_Serial是...
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()具有无限循环,因此它必须作为线程工作
所以我这样使SendAndRecv()
public string SendAndRecv(string sendPkt)
{
string recvPkt = "";
serialWrite(sendPkt);
Thread th = new Thread(() => recvPkt = waitDataReceived());
th.Start();
th.Join();
return recvPkt;
}
但是Join()是无限循环时的块UI。
我对此进行了搜索,然后发现了异步/等待状态。
所以我修改了SendAndRecv()
public async Task<string> SendAndRecv(string sendPkt)
{
string recvs = "";
serialWrite(sendPkt);
recvs = await Task.Run(() => waitDataReceived());
return recvs;
}
并且像这样在CommunicationJob()中使用
recvMsg = SendAndRecv(sendPkt[i]).Result;
但是它仍然阻止UI。即使无限循环中断,也不会释放。
也不要在CommunicationJob()中打印recvMsg。
程序停止。
如何使用线程不阻塞UI并等待直到返回值?
答案 0 :(得分:2)
您需要整理模式,直到您的GUI单击方法为止。在继承行(调用层次结构)中,每种方法必须异步并使用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);
}
这应该确保UI不会冻结。
实际上,您可以在return
语句之后直接写等待:
public async Task<string> SendAndRecv(string sendPkt)
{
string recvs = "";
serialWrite(sendPkt);
return await Task.Run(() => waitDataReceived());;
}
答案 1 :(得分:1)
不仅必须使SendAndRecv
异步,还必须使其所有呼叫者以及这些呼叫者的呼叫者(依此类推)async
。并且,当您调用async
方法时,您将使用await
。
因此,CommunicationJob
应该是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;
}
并且btnRead_Click
应该是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);
}