Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# NET中的多线程和闭包_C#_.net_Multithreading_Closures - Fatal编程技术网

C# NET中的多线程和闭包

C# NET中的多线程和闭包,c#,.net,multithreading,closures,C#,.net,Multithreading,Closures,如果我有这个: public string DoSomething(string arg) { string someVar = arg; DoStuffThatMightTakeAWhile(); return SomeControl.Invoke(new Func<string>(() => someVar)); } 公共字符串DoSomething(字符串arg) { 字符串someVar=arg; 可能需要一段时间的剂量(); 返回SomeCo

如果我有这个:

public string DoSomething(string arg)
{
    string someVar = arg;
    DoStuffThatMightTakeAWhile();
    return SomeControl.Invoke(new Func<string>(() => someVar));
}
公共字符串DoSomething(字符串arg)
{
字符串someVar=arg;
可能需要一段时间的剂量();
返回SomeControl.Invoke(newfunc(()=>someVar));
}
这个方法可以从多个线程并发调用,其中一个线程停留在
dostuff,这可能需要一段时间
,然后第二个线程用不同的
arg
调用
DoSomething
,这会改变所有线程的
someVar
的值,因此,
DoSomething
在两个调用上都返回第二个版本的
someArg
,或者每个线程都存在一个
someVar


编辑我认为我的
操作
应该是一个
函数
因此对其进行了编辑。

局部变量存储在当前线程的堆栈中,因此每个线程都有自己的堆栈和其中的
someVar
变量

因为每个线程中的值不同

new Action(() => someVar)); 
将捕获它自己的
someVar

编辑


正如埃里克指出的那样,我这么说完全是错的。查看他的答案以获得正确的解释。

如前所述,每个命中
DoSomething
的线程都在其堆栈上创建一个单独的
someVar
,因此没有线程对另一个
someVar
有任何影响

但是值得注意的是,如果在闭包中捕获了一个局部,并且在该范围内启动了多线程,那么这确实会导致不同的线程影响彼此看到的值,即使是在值类型的情况下(我们通常认为这不是另一个方法可以影响的东西-通过这种方式闭包与类方法不同:

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();
}

这说明了这一点。

这里的答案中有许多混淆,主要是因为“在线程堆栈上”分配局部变量是不真实的。这是错误的和不相关的

这是错误的,因为局部变量可能被分配到某个临时池或长期存储池上;即使它被分配到临时池上,也不必是堆栈内存;它可以是寄存器。这无关紧要,因为谁在乎在哪个池上分配存储

相关事实是,每个方法激活分配一个顶级局部变量。更一般地说,块中的局部变量在每个输入的块中分配一次;例如,循环体中声明的局部变量在每次循环循环时分配

所以,让我们考虑一下你的问题:

可以从多个线程并发调用此方法。如果一个线程在dostuff处卡住,可能需要一段时间,然后第二个线程使用不同的参数调用DoSomething,这会更改所有线程的someVar值吗

否。每次激活剂量测定都有一个新的“someVar”

每个线程是否存在一个someVar

每个激活都会有一个“someVar”。如果一个线程只进行了一次激活,那么每个线程将有一个someVar;如果一个线程进行了一百万次激活,那么将有一百万次激活


这就是说,Jon Hanna的答案也是正确的:如果你让一个代理同时读写一个局部变量,然后你将该代理交给多个线程,那么该代理的所有激活都共享同一个局部变量。没有为你创造神奇的线程安全;如果你想这样做,那么你就要对它负责确保线程安全。

表示“局部变量存储在当前线程的堆栈上”不正确。在闭包中捕获的任何变量都在堆上分配。Jason是正确的。这个答案没有合理的逻辑。是的,我的错,我不会修改我的答案,因为你的答案非常好。如果我理解正确,在你的示例中只有一个
x
(在主线程中创建的一个)每个线程都在访问它?确切地说,手动创建的线程会不断将它写入控制台,而主线程会增加它。请注意,someVar并不是首先在堆栈上分配的。封闭局部变量是在堆上分配的,因为它们的生存期延长了。是的。@EricLippert简洁地说了一些不正确的话当我发表文章的时候,我的第一句话并没有完全正确。事实上,我的第一句话错误地说了相反的话,尽管在这种情况下,生命周期并没有延长,但就多线程而言,逻辑上是一样的,我的观点是,有时只有一个线程可以看到适用于局部变量的推理仍然适用,有时则不适用几句话,像
string myVar;
这样的声明将创建一个新的
myVar
就像我用
new
关键字创建一个对象一样?这是否也适用于递归调用(如果
DoSomething
将调用
DoSomething
)?@jsoldi:内存分配器创建新局部变量的方式和它为对象创建新存储的方式在幕后可能非常不同,但在概念上它们是相同的。是的,递归调用和非递归调用一样都是激活。每个激活都会得到一批新的局部变量。为什么称之为“方法激活”而不是“方法调用”。这是一个特殊的术语吗?