How to stop a thread when a new one is initiated?

104 Views Asked by At

I'm improving the performance of a 3d engine i created, introducing LockBits and parallel processing. I have a class for the engine with the following method to update a bitmap with the result:

 public void draw() {

        clearbmp();

        // locking bmp
        BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, W, H), ImageLockMode.ReadWrite, bmp.PixelFormat);
        IntPtr FirstPixel = bitmapData.Scan0;
        int bytes = Math.Abs(bitmapData.Stride) * H;
        bpp = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8;
        rgbarray = new byte[bytes];
        System.Runtime.InteropServices.Marshal.Copy(FirstPixel, rgbarray, 0, bytes);

        int count = 0;
        for (int k = 0; k < solidos.Count; k++)
        {
            if (solidos[k] != null && solidos[k].draw)
            {
                // separating faces of the solid into different threads
                Parallel.ForEach(solidos[k].side, f =>
                {
                    // ... do the operations...
                });
            }
        }

        // copy the array to the bitmap and unlock
        System.Runtime.InteropServices.Marshal.Copy(rgbarray, 0, FirstPixel, bytes);
        bmp.UnlockBits(bitmapData);

The code runs as intended to generate a image, but fails when the main program requires it to update several times in a quick succession, the error occurs in bmp.UnlockBits(bitmapData) with the excepion "Generic error in GDI+"

From what i gathered from my research I suppose this happens because the method runs a second time before it finished the first one, thus trying to unlock data that is already unlocked.

If that is correct then how can i abort the running thread when the new one is created? The last call is always the important one

1

There are 1 best solutions below

0
On
  1. Before starting a new call, wait for the existing call to complete. You could do that by simply using a lock region. This solves the correctness issue. Maybe it's easier to make each computation run into a Task using Task.Run. The resulting Task object is a handle to that computation and can be used to wait for it to complete.
  2. If you want to speed up finishing an old computation run that is no longer needed, add a cancellation mechanism. Here, you could use a volatile bool cancel = false;. Set it to true to cancel. In your parallel loop (and possibly elsewhere), check that boolean variable periodically and terminate if it is found true. You can also use a CancellationTokenSource.