嗨,我正在阅读"C#中的线程化"教程.它提到的一件事是:
"CLR为每个线程分配自己的内存堆栈,以便局部变量保持独立"
还有这个例子:
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
for (int i = 0; i < 20; i++) {
Thread t = new Thread(() => {
Console.WriteLine(i);
});
t.Start();
}
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
}
输出:1 2 2 4 6 8 10 10 10 10 12 12 14 15 17 18 18 20 20
所以我理解这里发生的事情的方式是:
作为"i"整数,我的猜测是新线程将在其内存堆栈中拥有自己的副本.然后将值打印到控制台.但是结果显示,它跳过的值从10跳到12或12到14.所以新线程是否正在接收对i的引用?但是如果"i"是一个整数,则新线程不应该在其内存堆栈中存储新值,而不是看起来像i的引用.
还有为什么有重复值?它的打印次数分别是2,10,12,18,20.
谢谢.
该样本存在致命缺陷...因为每个线程实际上都在共享一个i变量.它被lambda表达式捕获.
这是一个非常常见的问题,但在线程教程中看到它真的很遗憾.(我希望这不是我的一篇文章!请告诉我们你在哪里读这篇文章.)Eric Lippert在他的博客文章中非常仔细地写了这篇文章,"关闭了认为有害的循环变量" - 第1部分 ; 第2部分.
值得区分线程行为和lambda表达式.线程真的做有自己的堆栈和自己的局部变量-但是在这里,i在所有线程之间共享由于lambda表达式.它不是"正常"意义上的局部变量.
这是一个示例,显示每个线程都有自己的局部变量:
using System;
using System.Threading;
public class Test
{
static void Main()
{
for (int x = 0; x < 10; x++)
{
new Thread(Count).Start();
}
}
static void Count()
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Thread {0} starting", threadId);
for (int i = 0; i < 5; i++)
{
Console.WriteLine("{0}: {1}", threadId, i);
}
Console.WriteLine("Thread {0} ending", threadId);
}
}
Run Code Online (Sandbox Code Playgroud)
每个线程肯定会打印0..4以及自己的线程ID.这次i变量对于每个线程都是真正的本地变量 - 没有共享.
| 归档时间: |
|
| 查看次数: |
776 次 |
| 最近记录: |