我在 backgroundworker 类中遇到了一些奇怪的行为,这让我相信我并不完全理解它是如何工作的。我假设以下代码部分或多或少是相同的,除了 BackgroundWorker 实现的一些额外功能(如进度报告等):
第 1 节:
void StartSeparateThread(){
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//Execute some code asynchronous to the thread that owns the function
//StartSeparateThread() but synchronous to itself.
var SendCommand = "SomeCommandToSend";
var toWaitFor = new List<string>(){"Various","Possible","Outputs to wait for"};
var SecondsToWait = 30;
//this calls a function that sends the command over the NetworkStream and waits
//for various responses.
var Result=SendAndWaitFor(SendCommand,toWaitFor,SecondsToWait);
}
第 2 节:
void StartSeparateThread(){
Thread pollThread = new Thread(new ThreadStart(DoStuff));
pollThread.Start();
}
void DoStuff(object sender, DoWorkEventArgs e)
{
//Execute some code asynchronous to the thread that owns the function
//StartSeparateThread() but synchronous to itself.
var SendCommand = "SomeCommandToSend";
var toWaitFor = new List<string>(){"Various","Possible","Outputs to wait for"};
var SecondsToWait = 30;
//this calls a function that sends the command over the NetworkStream and waits
//for various responses.
var Result=SendAndWaitFor(SendCommand,toWaitFor,SecondsToWait);
}
我正在使用第 1 节运行一些代码,这些代码通过网络流发送字符串并等待所需的响应字符串,并在此期间捕获所有输出。我编写了一个函数来执行此操作,该函数将返回网络流输出、发送字符串的索引以及所需响应字符串的索引。我看到了一些奇怪的行为,所以我将函数更改为仅在找到发送字符串和输出字符串时返回,并且找到的字符串的索引大于发送的字符串的索引。否则它将永远循环(仅用于测试)。我会发现该函数确实会返回,但两个字符串的索引都是 -1 并且输出字符串为空,或者有时填充了前一次调用的预期输出。如果我要猜测发生了什么,从 bw_DoWork() 函数内部调用的外部函数将与拥有 bw_DoWork() 函数的线程异步运行。结果,由于我的 SendAndWaitFor() 函数被连续多次调用。第二次调用将在第一次调用完成之前运行,在返回后覆盖第一次调用的结果,但在它们可以被评估之前。这似乎是有道理的,因为第一次调用总是会正确运行,而后续调用会显示上述奇怪的行为,但这似乎与 BackgroundWorker 类的行为方式背道而驰。此外,如果我在 SendAndWaitFor 函数内中断,事情会正常运行。这再次让我相信在 bwDoWork 函数本身中存在一些多线程。
当我将上面第一部分的代码更改为第二部分的代码时,事情完全按预期工作。那么,任何了解 BackgroundWorker 类的人都可以解释可能发生的情况吗?以下是一些可能相关的相关功能。
谢谢!
public Dictionary<string, string> SendAndWaitFor(string sendString, List<string> toWaitFor, int seconds)
{
var toReturn = new Dictionary<string, string>();
var data = new List<byte>();
var enc = new ASCIIEncoding();
var output = "";
var FoundString = "";
//wait for current buffer to clear
output = this.SynchronousRead();
while(!string.IsNullOrEmpty(output)){
output = SynchronousRead();
}
//output should be null at this point and the buffer should be clear.
//send the desired data
this.write(enc.GetBytes(sendString));
//look for all desired strings until timeout is reached
int sendIndex=-1;
int foundIndex = -1;
output += SynchronousRead();
for (DateTime start = DateTime.Now; DateTime.Now - start < new TimeSpan(0, 0, seconds); )
{
//wait for a short period to allow the buffer to fill with new data
Thread.Sleep(300);
//read the buffer and add it to the output
output += SynchronousRead();
foreach (var s in toWaitFor)
{
sendIndex = output.IndexOf(sendString);
foundIndex = output.LastIndexOf(s);
if (foundIndex>sendIndex)
{
toReturn["sendIndex"] = sendIndex.ToString();
toReturn["foundIndex"] = sendIndex.ToString();
toReturn["Output"] = output;
toReturn["FoundString"] = s;
return toReturn;
}
}
}
//Set this to loop infinitely while debuging to make sure the function was only
//returning above
while(true){
}
toReturn["sendIndex"]="";
toReturn["foundIndex"]="";
toReturn["Output"] =output;
toReturn["FoundString"] = "";
return toReturn;
}
public void write(byte[] toWrite)
{
var enc = new ASCIIEncoding();
var writeString = enc.GetString(toWrite);
var ns = connection.GetStream();
ns.Write(toWrite, 0, toWrite.Length);
}
public string SynchronousRead()
{
string toReturn = "";
ASCIIEncoding enc = new ASCIIEncoding();
var ns = connection.GetStream();
var sb = new StringBuilder();
while (ns.DataAvailable)
{
var buffer = new byte[4096];
var numberOfBytesRead = ns.Read(buffer, 0, buffer.Length);
sb.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, numberOfBytesRead));
toReturn += sb.ToString();
}
return toReturn;
}