Click here to Skip to main content
15,885,366 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I am creating new thread everytime in the for loop .. but many times the loop takes the same filename in new thread.

Doesn't Work:

foreach (string s in fileEntries)
{
    t = new Thread(() => Shrink(s));
    t.Start();
}


I have tried individually for each file creating new thread hard coded providing the file name and it works fine.

Working / Needed:

Thread t = new Thread(() => Shrink(@"C:\abc.doc"));
t.Start();
Thread t1 = new Thread(() => Shrink(@"C:\123.doc"));
t1.Start();


But i have to take all the files in from a selected directory and create new thread for each in a loop.

Help would be appreciated.
Thanks

[edit]Inline code changed for Code Block - OriginalGriff[/edit]
Posted
Updated 21-Feb-11 4:45am
v3
Comments
Sergey Alexandrovich Kryukov 21-Feb-11 12:13pm    
Despite of insane code, this question makes a wonderful question, my 5.
--SA

0) You should use a thread pool so that your app doesn't bog down the system trying to process all of the files at the same time.

1) Stop using lamba expressions so that your code is easier to work on.

2) I would do it this way:

C#
foreach (string file in fileEntries)
{
   Thread t = new THread(new ParameterizedThreadStart(Shrink));
   t.Start(file);
}

private void Shrink(object fileName)
{
    string file = fileName as string;
    // ... do something with file
}


Once again, I recommend using a thread pool. Google is your friend (I use the SmartThreadPool code which is widely available - including source code).
 
Share this answer
 
Comments
Olivier Levrey 21-Feb-11 12:06pm    
Voted 5. Safer, for sure.
Sergey Alexandrovich Kryukov 21-Feb-11 12:42pm    
Hi John,
I did not vote for your answer this time.
The essence of the effect is related to closures. Please see Nishant's answer and mine.
I disagree with you advice of lambda. In all my experience, this form of delegate simply makes no difference with other form of anonymous (through keyword "delegate").
Cheers,
--SA
Member 4581741 22-Feb-11 8:21am    
No John is right too. Eliminating lamda makes it simpler to use. I just tried ParameterizedThreadStart and it eliminated my error too without assigning it to temporary string.
Think lamda functions in a different way.
Yes, that's a side effect of using an anonymous function there (which results in variable capture).

Change your code to use a local variable:

C#
foreach (string s in fileEntries)
{
  string tmp = s;
  var t = new Thread(() => Shrink(tmp));
  t.Start();
}


[Update]
~~~~~~~~~

And yeah, while this will fix your problem, I would recommend following John's recommendations too.
 
Share this answer
 
v2
Comments
Olivier Levrey 21-Feb-11 12:03pm    
Voted 5. I didn't know this side effect concerning lambda expressions! Interresting.
Sergey Alexandrovich Kryukov 21-Feb-11 12:07pm    
OP commented:

Yup .. that worked ..

Thanks for help.

But i am still wondering that how adding a string tmp variable and passing that to the function worked.
Nish Nishant 21-Feb-11 12:11pm    
Thanks SA. If I reply to this comment, I don't think the OP will even get notified. Which is a pity.
Sergey Alexandrovich Kryukov 21-Feb-11 12:39pm    
Nishant, this is all about closures. I tried to answer.
John is not quite right.
--SA
Sergey Alexandrovich Kryukov 21-Feb-11 12:40pm    
My 5 for your answer, by the way. This is correct.
I love the question as well.
--SA
I'm answering the follow-up question:

But i am still wondering that how adding a string tmp variable and passing that to the function worked.
To get an idea, you should better understand what a closure is: http://en.wikipedia.org/wiki/Closure_(computer_programming)[^].

Let's consider all the detail of the call, but simplify and change is it:

C#
void TestThread() {
    string stackVariable = "My variable";
    t = new Thread(() => Shrink(stackVariable));
    t.Start();
    stackVariable = "New value";
}


What happens with the variable stackVariable? Normally, when you call a method, its local variables are created on stack and are discarded after the call. But how the code above can possible work?

The value of stackVariable may be needed even after the call to TestThread, because nobody knows when a time slice for the thread starts. So the local variable is not local anymore. There is a special mechanism that suspend removal of local variables. It is kind of "promoted" to a static variable only for the sake of being accessible to a delegate. This effect can only come in play with anonymous methods and has nothing to do with threads. Also, lambda form of the delegate makes no difference; the only essential factor is using anonymous method.

Not try to analyze the absurdism of the situation with loop variable. Normally, the loop variable is designed to be stack-only. You force the lifetime of the variable to be prolonged even beyond the loop block, as it is used by a thread. (By the way, I once found, this is the only way to check what happens with the loop variable when execution goes out to the loop block where it is not accessible "officially").

To simplify the situation, let's make a sample of using of this effect without threads, even without parameters:

C#
void SetupLocalVaribleCount() {
    int localCounter = 0;
    MyButton.Click += (sender, eventArg) => {
        localCounter++;
        MyForm.Text = string.Format("Clicked {0} times", localCounter);
    } //MyButton.Click 
}


Can you see what's going on? You call SetupLocalVaribleCount and return before the user clicks the button. When the click happens, the variable localCounter is still used even though the stack frame of SetupLocalVaribleCount is gone forever. This code will really work and count clicks using the variable which is "officially" local and would be created on stack and removed if not the anonymous delegate using it.

You should not be afraid of using anonymous methods, with lambda or not, or closures, for that matter, but you need to understand the subtle consequences of it.

—SA
 
Share this answer
 
v4
Comments
Nish Nishant 21-Feb-11 12:30pm    
Voted 5! Excellent response.
Sergey Alexandrovich Kryukov 21-Feb-11 12:44pm    
Thank you, Nishant.
This stuff is really hard to explain because it breaks some stereotypes in pieces.
We also use the jargon term "ripping of a template".
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900