-1

我有以下代码:

    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处理掉的同步问题吗?如果没有,我怎样才能正确地将多个参数传递给一个线程以用作线程池的一部分?

4

2 回答 2

2

为什么你必须创建一个类?你可以这样做:

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

该语言将在幕后为您创建一个类作为“闭包”。

于 2012-07-26T15:24:49.070 回答
2

尝试在循环内部x使用本地副本:y

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值。

于 2012-07-26T15:54:13.227 回答