Parallel Computing Developer Center >
Parallel Computing Forums
>
Parallel Extensions to the .NET Framework
>
Different output of 2 seemingly same code snippet
Different output of 2 seemingly same code snippet
- Consider following console application:Assume that I have four files in "D:\Test" folder: "1.txt", "2.txt", "3.txt", "4.txt".
class Program { static void Main (string[] args) { string targetPath = @"D:\Test"; var files = Directory.GetFiles (targetPath); //Parallel method Parallel.ForEach (files, f => Console.WriteLine (f)); //Classic method foreach (string f in files) Task.Factory.StartNew (() => Console.WriteLine (f)); Console.ReadLine (); } }When I run about program, first method i.e. Parallel method prints (correctly):D:\Test\1.txtD:\Test\2.txtD:\Test\3.txtD:\Test\4.txtBut the classic method prints:D:\Test\4.txtD:\Test\4.txtD:\Test\4.txtD:\Test\4.txtWhy do classic way doesn't work whereas Parallel one does?P.S.: Please let me know if you need me to explain why do I need to use classic foreach.
Answers
- You are falling fowl of the typical anonymous methods state capture..The object created for the anonymous method is bound to the loop variable, when this executes asynchronously you get the value of the loop variable at the given point in time when the Console.WriteLine executes.If you wish to use the value as is at the point of task creation you need to capture a local variable of the loop.
simply add//Classic method foreach (string f in files)
{string filename = f;Task.Factory.StartNew (() => Console.WriteLine (filename));}- Marked As Answer byHemant Jangid Thursday, October 15, 2009 4:42 AM
All Replies
- I thought all tasks launched by classic foreach are referencing same string. So I tried with different instances:But even this doesn't work. I get same output:
//Classic method foreach (string f in files) Task.Factory.StartNew (() => Console.WriteLine (String.Copy (f)));
D:\Test\4.txtD:\Test\4.txtD:\Test\4.txtD:\Test\4.txt - You are falling fowl of the typical anonymous methods state capture..The object created for the anonymous method is bound to the loop variable, when this executes asynchronously you get the value of the loop variable at the given point in time when the Console.WriteLine executes.If you wish to use the value as is at the point of task creation you need to capture a local variable of the loop.
simply add//Classic method foreach (string f in files)
{string filename = f;Task.Factory.StartNew (() => Console.WriteLine (filename));}- Marked As Answer byHemant Jangid Thursday, October 15, 2009 4:42 AM
- Thanks for the answer. It worked.I must say this is the first time I have touched a dark corner of C#. Most of the time it works as you expect it to.


