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. 😉


Anmelden zum Antworten