使用线程池的多线程

时间:2012-07-26 15:22:18

标签: c# multithreading c#-4.0 taskfactory

我有以下代码:

    private static void SplitTilesRecursive(Image original, int level)
    {
        int mapWidth = GetMapWidth(level);
        int tilesOnSide = mapWidth/TileSize;


        using (Image resized = ResizeImage(original, new Size(mapWidth, mapWidth)))
        {
            for (int x = 0; x < tilesOnSide; x++)
                for (int y = 0; y < tilesOnSide; y++)
                {
                    CropAndSaveTile(resized, x, y, level);
                }
        }


        if (level > 0)
            SplitTilesRecursive(original, level - 1);
    }

    private static void CropAndSaveTile(Image image, int x, int y, int level)
    {
        var info = (CropInfo) o;
        var cropArea = new Rectangle(x * TileSize, y * TileSize, TileSize, TileSize);


        using (var bmpImage = new Bitmap(image))
        using (Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat))
        {
            string filename = String.Format(TileFilename, level, x, y);

            // the Portable Network Graphics (PNG) encoder is used implicitly
            bmpCrop.Save(Path.Combine(OutputDir, filename));
            Console.WriteLine("Processed " + filename);
        }
    }

方法CropAndSaveTile需要一段时间,因此我想使用线程池将该任务拆分为新线程。我试图使用Task.Factory.StartNew来完成此任务。问题是我需要将这4个参数传递给线程,所以我必须创建一个可以转换为对象的类。

    private class CropInfo
    {
        public CropInfo(Image image, int x, int y, int level)
        {
            Image = image;
            X = x;
            Y = y;
            Level = level;
        }

        public Image Image { get; set; }
        public int X { get; set; }
        public int Y { get; set; }
        public int Level { get; set; }
    }

    private static void SplitTilesRecursive(Image original, int level)
    {
        // ...
        using (Image resized = ResizeImage(original, new Size(mapWidth, mapWidth)))
        {
            for (int x = 0; x < tilesOnSide; x++)
                for (int y = 0; y < tilesOnSide; y++)
                {
                    Task.Factory.StartNew(CropAndSaveTile, new CropInfo(resized, x, y, level));
                }
        }
        // ...
    }

    private static void CropAndSaveTile(object o)
    {
        var info = (CropInfo) o;
        // ...
    }

这几乎可行。问题是new Bitmap(info.Image)抛出ArgumentException(参数无效)。我已经在不使用Task.Factory.StartNew的情况下对此进行了测试,而是使用CropAndSaveTile(new CropInfo(resized, x, y, level));直接调用该方法,并且工作正常。 StartNew和线程之间发生了一些事情。这可能是SplitTilesRecursive结束循环并导致resized处理时导致的同步问题吗?如果没有,我如何正确地将多个参数传递给线程以用作线程池的一部分?

2 个答案:

答案 0 :(得分:2)

为什么要创建课程?你可以这样做:

Task.Factory.StartNew(()=>CropandSaveTile(resized, y, y,  level));

该语言将为您创建一个课程作为“封闭”。

答案 1 :(得分:2)

尝试在循环中使用xy的本地副本:

for (int x = 0; x < tilesOnSide; x++)
    for (int y = 0; y < tilesOnSide; y++)
    {
        int x1 = x;
        int y1 = y;
        Task.Factory.StartNew(() => CropAndSaveTile(resized, x1, y1, level));
    }

这可以保证每个lambda都会看到一对独立的xy值。