循环创建新线程会带来一些问题 [英] Looping for creating new thread give some problem

查看:213
本文介绍了循环创建新线程会带来一些问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我每次都在for循环中创建新线程..但很多时候,循环在新线程中使用相同的文件名.

不起作用:

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



但是我必须从选定目录中提取所有文件,并为每个文件创建新线程.

帮助将不胜感激.
谢谢

代码块的内联代码已更改-OriginalGriff [/edit]



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]

推荐答案

0)您应使用线程池,以使您的应用不会陷入困境系统尝试同时处理所有文件.

1)停止使用lamba表达式,以便您的代码更易于使用.

2)我会这样:

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:

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
}



再一次,我建议使用线程池. Google是您的朋友(我使用的是SmartThreadPool代码,该代码广泛使用-包括源代码).



Once again, I recommend using a thread pool. Google is your friend (I use the SmartThreadPool code which is widely available - including source code).


是的,那是在其中使用匿名函数的副作用(这会导致变量捕获).

更改代码以使用局部变量:

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:

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.


我正在回答以下问题:

但是我仍然想知道如何添加字符串tmp变量并将其传递给函数.
要想出一个主意,您应该更好地了解什么是闭包: http://en.wikipedia.org /wiki/Closure_(computer_programming) [ ^ ].

让我们考虑通话的所有细节,但简化和更改就可以了:

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:

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



变量stackVariable会发生什么?通常,当您调用方法时,其局部变量是在堆栈上创建的,并且在调用后将被丢弃.但是上面的代码如何工作呢?

即使在调用TestThread之后,也可能需要stackVariable的值,因为没有人知道线程的时间片何时开始.因此,局部变量不再是局部变量.有一种特殊的机制可以挂起局部变量的删除.仅出于委托可访问的目的,它被提升"为静态变量.此效果只能与匿名方法一起使用,与线程无关.同样,委托的lambda形式也没有区别;唯一必要的因素是使用匿名方法.

不要试图用循环变量来分析这种情况的荒谬性.通常,循环变量被设计为仅堆栈.您强制变量的寿命甚至延长到循环块之外,因为线程会使用它. (顺便说一句,我曾经发现,这是检查执行到无法正式"访问的循环块时循环变量会发生什么情况的唯一方法.)

为了简化这种情况,让我们示例使用这种效果的示例,该示例在没有线程甚至没有参数的情况下也是如此:



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:

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



你能看到发生了什么吗?您调用SetupLocalVaribleCount并在用户单击按钮之前返回.当单击发生时,即使SetupLocalVaribleCount的堆栈框架已永远消失,仍将使用变量localCounter.该代码将真正有效并使用官方"本地变量来计算点击次数,该变量将在堆栈上创建,如果不是使用匿名委托的变量,则将其删除.

为此,您不应该担心使用带有lambda或不带有 closures 的匿名方法,但是您需要了解它的微妙后果.

—SA



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


这篇关于循环创建新线程会带来一些问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆