.NET中的multithreading和闭包
如果我有这个:
public string DoSomething(string arg) { string someVar = arg; DoStuffThatMightTakeAWhile(); return SomeControl.Invoke(new Func(() => someVar)); }
并且这个方法可以从多个线程同时调用,并且一个线程停留在DoStuffThatMightTakeAWhile
,然后第二个线程调用具有不同arg
DoSomething
,这将改变所有线程的someVar
的值,因此, DoSomething
返回第二个版本的两个调用中的someArg
,或者每个线程someVar
存在一个someVar
吗?
编辑我认为我的Action
应该是一个Func
所以编辑它。
这里的答案中存在许多混淆,主要是基于“在线程堆栈上”分配局部变量的不实之处。 这既虚假又无关紧要。
这是错误的,因为局部变量可能分配在某个临时池或长期存储池中; 即使它是在临时池上分配的,也不需要堆栈内存; 它可能是一个注册。 这是无关紧要的,因为谁关心分配存储的池?
相关的事实是每个方法激活分配一个顶级局部变量。 更一般地,块中的局部变量按输入的块分配一次; 例如,每当循环遍历时,就会在循环体中声明一个局部变量。
那么,让我们考虑你的问题:
可以从多个线程同时调用此方法。 如果一个线程停留在DoStuffThatMightTakeAWhile,然后第二个线程调用具有不同arg的DoSomething,这会改变所有线程的someVar的值吗?
不。 每次激活 DoSomething 都会有一个新的“someVar”。
每个线程都会存在一个someVar吗?
每次激活都会存在一个“someVar”。 如果一个线程只执行一次激活,那么每个线程将只有一个someVar; 如果一个线程进行了一百万次激活,那么将有一百万次激活。
也就是说,Jon Hanna的回答也是正确的:如果你创建了一个既读取又写入局部变量的委托 ,又将该委托交给多个线程,那么委托的所有激活共享相同的局部变量。 没有为您创造神奇的线程安全; 如果你想这样做,那么你有责任确保线程安全。
局部变量存储在当前线程的堆栈中,因此每个线程都有自己的堆栈,并且每个线程都拥有someVar
变量。
因为每个线程中的值都不同
new Action(() => someVar));
将捕获它自己的someVar
值。
编辑
埃里克指出,我完全错了。 请参阅他的答案以获得正确的解
如上所述,每个线程击中DoSomething
someVar
在其堆栈上创建一个单独的someVar
,因此没有线程对另一个的someVar
有任何影响。
值得注意的是,如果在闭包中捕获了本地并且在该作用域中启动了multithreading,则这确实会导致不同的线程影响彼此看到的值,即使在值类型的情况下(我们通常认为不是另一种方法可以影响的东西 – 这样闭包不像类方法:
public static void Main(string[] args) { int x = 0; new Thread(() => {while(x != 100){Console.WriteLine(x);}}).Start(); for(int i = 0; i != 100; ++i) { x = i; Thread.Sleep(10); } x = 100; Console.ReadLine(); }
certificate了这一点。