使用线程池工作时,有人可以解释这种奇怪的行为? [英] Can somebody explain this odd behavior when working with ThreadPool?

查看:154
本文介绍了使用线程池工作时,有人可以解释这种奇怪的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

using System;
using System.Threading;

public delegate void LoadingProgressCallback(double PercentComplete,string ItemName);
public delegate void LoadCompleteCallback(int ItemID, string ItemName);

public static class Program
{
    public static void Main(string[] args)
    {
        LoadTest loadTest = new LoadTest();
        loadTest.LoadItems(args);
    }
}

public class LoadTest
{       
    ManualResetEvent resetEvent;
    int numThreads = 0;

    public LoadTest()
    {}

    public void LoadItems(string[] Items)
    {
        numThreads = 0;
        resetEvent = new ManualResetEvent(false);

        foreach(string item in Items)
        {
            Console.WriteLine("Adding {0} to ThreadPool",item);
            ThreadPool.QueueUserWorkItem
            (
                delegate
                {
                    Load(item, this.progCall, this.compCall);
                }
            );
            numThreads++;

            Thread.Sleep(100);//Remove this line

        }
        resetEvent.WaitOne();
    }

    public void progCall(double PercentComplete, string ItemName)
    {
        Console.WriteLine("{0}: is {1}% Complete [THREAD:{2}]",ItemName,PercentComplete.ToString(),Thread.CurrentThread.ManagedThreadId.ToString());
    }
    public void compCall(int ItemID, string ItemName)
    {
        Console.WriteLine("{0}: is Complete",ItemName);
        numThreads--;
        if(numThreads == 0)
        {
            resetEvent.Set();
        }
    }

    public void Load(string Item, LoadingProgressCallback progressCallback, LoadCompleteCallback completeCallback)
    {
        Console.WriteLine("Loading: {0} [THREAD:{1}]",Item,Thread.CurrentThread.ManagedThreadId.ToString());

        for(int i = 0; i <= 100; i++)
        {
            if(progressCallback != null)
            {
                progressCallback((double)i, Item);
            }
            Thread.Sleep(100);
        }
        if(completeCallback != null)
        {
            completeCallback(0,Item);
        }
    }
}

观察

如果我在命令行中运行这个程序,像这样...

Observation

If I run this program from the command line, like this...

&GT; TheProgram ITEM1 ITEM2

输出将这个样子。

添加到item1的线程池结果
  加载:项目1 [线索:3]结果
  ITEM1:为0%
  完成[主题:3]结果
  添加到ITEM2线程池结果
  装载:ITEM2 [线索:4]结果
  ITEM2:0%完成[线索:4]结果
  ITEM1:为1%完成[线索:3]结果
  ITEM2:为1%完成[线索:4]结果
  ITEM1:2%完成[线索:3]结果
  ITEM2:2%完成[线索:4]

Adding item1 to ThreadPool
Loading: item1 [THREAD:3]
item1: is 0% Complete [THREAD:3]
Adding item2 to ThreadPool
Loading: item2 [THREAD:4]
item2: is 0% Complete [THREAD:4]
item1: is 1% Complete [THREAD:3]
item2: is 1% Complete [THREAD:4]
item1: is 2% Complete [THREAD:3]
item2: is 2% Complete [THREAD:4]

不过,如果我删除此行。

However, if I remove this line.

Thread.sleep代码(100); //删除此行

LoadItems 方法,输出看起来是这样的。

From the LoadItems method, the output looks like this.

添加到item1的线程池结果
  添加到ITEM2线程池结果
  装载:ITEM2 [线索:4]结果
  装载:ITEM2 [线索:3]结果
  ITEM2:0%完成[线索:4]结果
  ITEM2:0%完成[线索:3]结果
  ITEM2:为1%完成[线索:4]结果
  ITEM2:为1%完成[线索:3]结果
  ITEM2:2%完成[线索:3]结果
  ITEM2:2%完成[线索:4]

Adding item1 to ThreadPool
Adding item2 to ThreadPool
Loading: item2 [THREAD:4]
Loading: item2 [THREAD:3]
item2: is 0% Complete [THREAD:4]
item2: is 0% Complete [THREAD:3]
item2: is 1% Complete [THREAD:4]
item2: is 1% Complete [THREAD:3]
item2: is 2% Complete [THREAD:3]
item2: is 2% Complete [THREAD:4]

它好像正在使用两个线程,但是它们都似乎是作用于相同的数据。为什么code这样的行为?

The Question

It seems as though two threads are being used, though they both seem to be acting on the same data. Why does the code behave this way?

推荐答案

您正在关闭了循环变量,它给你一个意想不到的结果。试试这个:

You're closing over the loop variable, which gives you an unexpected result. Try this instead:

foreach(string item in Items)
{
    string item2 = item;
    Console.WriteLine("Adding {0} to ThreadPool", item2);
    ThreadPool.QueueUserWorkItem
    (
        delegate
        {
            Load(item2, this.progCall, this.compCall);
        }
    );
    numThreads++;

    Thread.Sleep(100);//Remove this line

}

参考

  • Closing over the Loop Variable in C#
  • Closing over the loop variable considered harmful

这篇关于使用线程池工作时,有人可以解释这种奇怪的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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