【发布时间】:2021-12-06 03:07:02
【问题描述】:
以下是关于我要做什么的简要说明:
我有 2 个按钮:Button_Auto 启动 backgroundWorker_Auto 和 Button_Manual 停止(应该停止)正在运行的 backgroundWorker_Auto 并启动另一个按钮 backgroundWorker_Manual。基本上,按钮应该允许用户在我的应用程序中的两种操作模式之间切换。自动和手动
private Button_Auto_Click(object sender, EventArgs e)
{
if (!backgroundWorker_Auto.IsBusy)
backgroundWorker_Auto.RunWorkerAsync();
}
private Button_Manual_Click(object sender, EventArgs e)
{
//some code to stop backgroundWorker_Auto..
if (!backgroundWorker_Manual.IsBusy)
backgroundWorker_Manual.RunWorkerAsync();
}
backgroundWorker_Auto 只是一个连接到服务器的 TCP 客户端,从另一个应用程序对服务器的 API 调用接收数据。
我见过很多使用迭代器取消后台工作者的解决方案,它会在每次迭代时检查CancellationPending 属性。但是,在我下面的代码中,backgroundworker 只是等待来自 TCP 服务器的数据。
public static TcpClient client;
private void backgroundWorker_Auto_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
try
{
NetworkStream nwStream = client.GetStream();
while (client.Connected)
{
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize); //CODE WAITS HERE!!
String responseData = String.Empty;
responseData = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
switch (responseData)
{
case "1":
//Do something;
break;
case "2":
//Do some other thing;
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message)
}
}
问题是当backgroundWorker_Auto 启动时,它会在int bytesRead 行等待从服务器接收数据。收到后,它会执行以下功能并返回与上述相同的侦听状态。因此,即使我从 Button_Manual 触发 CancelAsync 并将 while 循环条件更改为 backgroundWorker_Auto.CancellationPending,除非客户端收到数据,否则不会对其进行检查。
而且由于backgroundWorker_Auto 没有停止,我将无法再次启动它,即无法在自动和手动之间切换。
如何在这种情况下检查CancellationPending 条件或正确停止backgroundWorker_Auto?
【问题讨论】:
-
使用
ReadAsync允许您使用取消令牌中止读取操作;同步版本没有这样做的好方法。您必须用异步方法替换后台工作程序,但现在这并不太复杂。 -
不要首先使用 BGW。该类已过时,10 年前完全被 async/await、Task.Run 和
IProgress取代。在这种情况下,TcpClient 和 NetworkStream 都提供异步方法。您可以用一个方法替换所有这些复杂的代码,该方法使用您放入DoWork和Stream.ReadAsync而不是Read等的内容 -
client.Close();完成工作,从按钮的 Click 事件中调用它。之后再次重新连接它,无论如何它都属于工人。 try/except 异常报错,属于RunWorkerCompleted事件处理函数,不报ObjectDisposedException。
标签: c# .net multithreading winforms backgroundworker