Multithreading .NET 4.0 BackgroundWorker类和异常行为

Multithreading .NET 4.0 BackgroundWorker类和异常行为,multithreading,c#-4.0,backgroundworker,Multithreading,C# 4.0,Backgroundworker,我在backgroundworker类中遇到了一些奇怪的行为,这让我相信我并不完全理解它是如何工作的。除了BackgroundWorker实现的一些额外特性(如进度报告等),我假设以下代码部分或多或少是相同的: 第1节: void StartSeparateThread(){ BackgroundWorker bw = new BackgroundWorker(); bw.DoWork += new DoWorkEventHandler(bw_DoWork

我在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);
    }
void StartSeparateThread(){
BackgroundWorker bw=新的BackgroundWorker();
bw.DoWork+=新DoWorkEventHandler(bw_DoWork);
RunWorkerAsync();
}
void bw_DoWork(对象发送方,DoWorkEventArgs e)
{
//执行一些与拥有函数的线程异步的代码
//StartSeparateThread()但与自身同步。
var SendCommand=“SomeCommandToSend”;
var toWaitFor=new List(){“各种”、“可能”、“要等待的输出”};
var SecondsToWait=30;
//这将调用通过NetworkStream发送命令并等待的函数
//对于各种反应。
var结果=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);
    }
void StartSeparateThread(){
线程pollThread=新线程(新线程开始(DoStuff));
pollThread.Start();
}
void DoStuff(对象发送器,DoWorkEventArgs e)
{
//执行一些与拥有函数的线程异步的代码
//StartSeparateThread()但与自身同步。
var SendCommand=“SomeCommandToSend”;
var toWaitFor=new List(){“各种”、“可能”、“要等待的输出”};
var SecondsToWait=30;
//这将调用通过NetworkStream发送命令并等待的函数
//对于各种反应。
var结果=SendAndWaitFor(SendCommand、toWaitFor、SecondsToWait);
}
我正在使用第1节运行一些代码,这些代码通过网络流发送字符串,并等待所需的响应字符串,在这段时间内捕获所有输出。为此,我编写了一个函数,该函数将返回networkstream输出、已发送字符串的索引以及所需响应字符串的索引。我看到了一些奇怪的行为,因此我将函数更改为仅在同时找到发送字符串和输出字符串时返回,并且找到的字符串的索引大于发送字符串的索引。否则它将永远循环(只是为了测试)。我会发现函数确实会返回,但两个字符串的索引都是-1,输出字符串为null,或者有时填充上一次调用的预期输出。如果我要猜测发生了什么,那么从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;
    }
公共字典SendAndWaitFor(字符串sendString,列表toWaitFor,整数秒)
{
var toReturn=新字典();
var data=新列表();
var enc=new ascienceoding();
var输出=”;
var FoundString=“”;
//等待当前缓冲区清除
输出=this.SynchronousRead();
而(!string.IsNullOrEmpty(输出)){
输出=SynchronousRead();
}
//此时输出应为空,缓冲区应为空。
//发送所需的数据
this.write(enc.GetBytes(sendString));
//查找所有需要的字符串,直到达到超时
int sendIndex=-1;
int foundIndex=-1;
输出+=同步读取();
for(DateTime start=DateTime.Now;DateTime.Now-startsendIndex)
{
toReturn[“sendIndex”]=sendIndex.ToString();
toReturn[“foundIndex”]=sendIndex.ToString();
返回[“输出”]=输出;
toReturn[“FoundString”]=s;
回归回归;
}
}
}
//在调试时将此设置为无限循环,以确保函数仅为
//返回上方
while(true){
}
返回[“发送索引”]=“”;
toReturn[“foundIndex”]=“”;
返回[“输出”]=输出;
返回[“FoundString”]=“”;
回归回归;
}
公共无效写入(字节[]到写入)
{
var enc=new ascienceoding();
var writeString=enc.GetString(toWrite);
var ns=connection.GetStream();
ns.写入(toWrite,0,toWrite.长度);
}
公共字符串同步器