-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

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

これにより、各ラムダがxとのy値の個別のペアを認識することが保証されます。

于 2012-07-26T15:54:13.227 に答える
2

なぜクラスを作成する必要があるのですか?これを行うことができます:

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

言語は、「クロージャー」としてカバーの下にクラスを作成します。

于 2012-07-26T15:24:49.070 に答える