【发布时间】:2018-06-18 14:48:44
【问题描述】:
背景
目前我正在编写一个程序,其中两个线程同时运行,每个线程都访问关键区域并向控制台写入一条消息。该程序涉及两个任务,我表示 1 和 2 基于定义为每个任务的局部变量的整数。这是创建和运行任务的代码 sn-p:
static void Main(string[] args)
{
Task[] tasks = new Task[2];
Mutex m;
// create the named mutex
m = new Mutex(false, "mutex_name");
// create two tasks that will each access the same critical region
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() =>
{
int iCopy = i;
int iterations = 20;
// run code that continuously enters the critical region
for (int j = 0; j < iterations; j++)
{
WriteConsole(m, iCopy);
}
});
}
// wait for all of the tasks to finish
foreach (var task in tasks)
{
task.Wait();
}
// wait for the user to exit the program
Console.ReadKey();
}
好的,请注意,我专门遵循了在每个任务上创建迭代变量的本地副本的做法。我已经这样做了,在过去的情况下,它提供了关闭。这一次,我最终得到的两个任务都包含值 2,这表明即使我已经制作了副本,变量仍然引用原始 for 循环。为什么?
另外,这里是WriteConsole函数的代码:
static void WriteConsole(Mutex m, int name)
{
// enter the critical region
m.WaitOne();
// acknowledge that we've entered the critical region
Console.WriteLine("Task: " + name + " has entered the critical region.");
// hold the mutex for a little while
Thread.Sleep(1000);
// acknowledge that we've left the critical region
Console.WriteLine("Task: " + name + " will now leave the critical region.");
// leave the critical region
m.ReleaseMutex();
}
这是上面的程序输出,我已经截断了一点,因为有这么多,因为显然我们处于一个循环中。在任何情况下,循环都会以每行打印 Task: 2:
结束Task: 2 已进入临界区。
Task: 2 现在将离开临界区。
Task: 2 已进入临界区。
Task: 2 现在将离开临界区。
Task: 2 已进入临界区。
“我尝试过的”
我尝试展开 for 循环以查看是否还有其他问题,或者这是否确实是循环/变量闭包的问题。当我展开循环时,我的输出看起来好多了:
Task: 0 已进入临界区。
Task: 0 现在将离开临界区。
Task: 1 已进入临界区。
Task: 1 现在将离开临界区。
Task: 0 已进入临界区。
Task: 0 现在将离开临界区。
Task: 1 已进入临界区。
Task: 1 现在将离开临界区。
Task: 0 已进入临界区。
Task: 0 现在将离开临界区。
Task: 0 已进入临界区。
Task: 0 现在将离开临界区。
Task: 1 已进入临界区。
Task: 1 现在将离开临界区。
当我说我已经展开 for 循环时,很可能知道我的意思,但我不会做任何假设,并为此包含代码 sn-p:
tasks[0] = Task.Run(() =>
{
int iterations = 20;
// run code that continuously enters the critical region
for (int j = 0; j < iterations; j++)
{
WriteConsole(m, 0);
}
});
tasks[1] = Task.Run(() =>
{
int iterations = 20;
// run code that continuously enters the critical region
for (int j = 0; j < iterations; j++)
{
WriteConsole(m, 1);
}
});
根据上述测试,此时看起来确实是一个关闭问题。现在,我要补充的最后一件事是,无论循环是否滚动/展开,两个任务都在执行。我已经能够设置断点,并看到任一任务在调试会话期间都按应有的方式执行。
问题
真正让我感动的是“创建本地副本”方法似乎没有提供闭包。
【问题讨论】:
标签: c# multithreading for-loop closures task