C# Threading/Lambda : Wo wird die Variable verändert?
-
Hallo Leute.
In folgender Methode nimmt i einen Wert == area.Width an, obwohl die Schleifenbedingung i < area.Width ist.
Wie kann das sein? i wird doch per Value dem Lambda zur Verfügung gestellt?
Was übersehe ich?public static Bitmap GenerateBitmap(Area area) { int maxIterations; double zBorder; double cReal, cImg, zReal, zImg, zNewReal, zNewImg; maxIterations = Settings.DefaultSettings.MaxIterations; zBorder = Settings.DefaultSettings.ZBorder * Settings.DefaultSettings.ZBorder; int elemCount = area.Width * area.Height; ConcurrentQueue<PixelInfo> queue = new ConcurrentQueue<PixelInfo>(); Semaphore sem = new Semaphore(0, elemCount); ThreadPool.SetMaxThreads(8, 8); for (int i = 0; i < area.Width; i++) { ThreadPool.QueueUserWorkItem((o) => { for (int j = 0; j < area.Height; j++) { cReal = area.MinReal + i * area.PixelWidth; cImg = area.MinImg + j * area.PixelHeight; zReal = 0; zImg = 0; int k = 0; while ((zReal * zReal + zImg * zImg < zBorder) && (k < maxIterations)) { zNewReal = zReal * zReal - zImg * zImg + cReal; zNewImg = 2 * zReal * zImg + cImg; zReal = zNewReal; zImg = zNewImg; k++; } queue.Enqueue(new PixelInfo(i, j, ColorSchema.GetColor(k))); sem.Release(); } }); } Bitmap bitmap = new Bitmap(area.Width, area.Height); int elemsProcessed = 0; while (elemsProcessed < elemCount) { sem.WaitOne(); PixelInfo pi; if (queue.TryDequeue(out pi)) { bitmap.SetPixel(pi.i, pi.j, pi.c); ++elemsProcessed; } else { MessageBox.Show("Oooooooops"); } } return bitmap; }
Vielen Dank & schöne Grüße,
Ethon
-
i wird nicht ins Lambda reinkopiert, sonder referenziert.
Und da i im Schleifenkopf definiert wird, und nicht im Body, ist es bei jedem Durchlauf die selbe Variable.Wenn du eine Kopie willst, musst du extra eine machen:
for (int i0 = 0; i0 < area.Width; i0++) { int i = i0; // i ist jetzt in jedem Durchlauf ne neue Variable, daher referenziert jetzt jede Lambda Expression ihre eigene Kopie ThreadPool.QueueUserWorkItem((o) => { for (int j = 0; j < area.Height; j++) { cReal = area.MinReal + i * area.PixelWidth; cImg = area.MinImg + j * area.PixelHeight; zReal = 0; zImg = 0; int k = 0; while ((zReal * zReal + zImg * zImg < zBorder) && (k < maxIterations)) { zNewReal = zReal * zReal - zImg * zImg + cReal; zNewImg = 2 * zReal * zImg + cImg; zReal = zNewReal; zImg = zNewImg; k++; } queue.Enqueue(new PixelInfo(i, j, ColorSchema.GetColor(k))); sem.Release(); } }); }
-
-
Okay, vielen Dank.
Merkt man mir wohl an, dass ich nur noch C++ und Java programmiere, bei ersterem kann man es genau steuern, bei Zweiterem ist die Referenz auf ein int ja garnicht möglich.