首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

为啥AutoResetEvent变量不能传递给线程

2012-09-24 
为什么AutoResetEvent变量不能传递给线程?实现多线程同时向多个目标地点发送一个文件。程序如下C# codeAuto

为什么AutoResetEvent变量不能传递给线程?
实现多线程同时向多个目标地点发送一个文件。

程序如下

C# code
AutoResetEvent[] are = new AutoResetEvent[releasePaths.Count];                        int _h = 0;            foreach (var item in releasePaths)            {                Console.WriteLine("In:_h={0}", _h);                are[_h] = new AutoResetEvent(false);                Thread thread = new Thread(() => item.SendFile("2012-9-11.zip", are[_h]));                _h++;                  thread.Start();            }             WaitHandle.WaitAll(are);


SendFile内部:
C# code
public bool SendFile(string from, AutoResetEvent autoRE = null)        {            try            {                if (lowPath.StartsWith("ftp://"))                {                    try                    {                        FTPclient ftpClient = new FTPclient(lowPath, User, Password);                        return ftpClient.Upload(from, lowPath);                    }                    catch (Exception)                    {                        return false;                    }                }                else                {                    if (!DstPath.EndsWith("\\"))                    {                        DstPath += "\\";                    }                    int times = 0;                    while (times < 10)                    {                        try                        {                            File.Copy(from, DstPath + System.IO.Path.GetFileName(from), true);                            return true;                        }                        catch (Exception e)                        {                            lock (ReleasePath._LockObj)                            {                                Log.WriteLog("Exception: " + e.Message);                            }                            Thread.Sleep(300000);                        }                        times++;                    }                    return false;                }            }            finally            {                if (autoRE != null)                {                    autoRE.Set();                }            }        }


一运行就报错:
Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at UpdateKav.Program.<>c__DisplayClass4.<Main>b__0()
  at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
  at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
  at System.Threading.ThreadHelper.ThreadStart()

我把
C# code
Thread thread = new Thread(() => item.SendFile("2012-9-11.zip", are[_h]));

改成
C# code
Thread thread = new Thread(() => item.SendFile("2012-9-11.zip", null));

并且把WaitHandle.WaitAll(are);这行注释掉,程序就OK。

求高手解释!

[解决办法]
索引越界,明显和AutoResetEvent无关啊。
---------------------------------------------
注意C#中闭包捕获的是“变量”,而不是“变量的当前值”。
你的代码中闭包捕获了are和_h两个变量,are是不会变化的,但是_h是会变的
_h最终的值是releasePaths.Count,超出了are的UpperBound,而后面创建的线程访问are[_h]时主线程很可能已经将_h的值更改为releasePath.Count了,所以高几率越界。
如果你是先创建所有线程,然后一起start(),所有线程在访问_h的时候它的值已经变成releasePaths.Count了,访问are[_h]百分百越界。
当然这里的“捕获变量”是从语意的角度来说的,编译器的实现并不是让lambda访问原始变量的地址。


---------------------------------------------
要改的话可以用一个封闭在foreach循环中的局部变量代替_h

C# code
int _h1=_h;//......Thread thread = new Thread(() => item.SendFile("2012-9-11.zip", are[_h1]));_h++; 

热点排行