RedSnoww
RedSnoww

Reputation: 1

How to abort a thread without Abort()?

In my Windows form application, I get a video stream from camera, and I want to display it in a picturebox of my form.

I have a list box that contains the cameras, I drag and drop in the picture box and it launches the function to retrieve the stream of the camera, it works, however when I set a new camera on the picture box, I mean that if the cam.IsAlive we cut all the thread. It never shuts down I also tried with a Task.

My lauchCam:

private void launchCam(PictureBox box, int numCam, CancellationToken ts)
        {
            

            VideoCapture video = new VideoCapture();

            video.Open(listCam[numCam].Url);
            using (Mat image = new Mat())
            {
                while (true)
                {
                    if (!video.Read(image))
                    {
                        Cv2.WaitKey();
                    }
                    if (listCam[numCam].Url != "")
                    {
                        Bitmap bitmap = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(image);
                        box.Image = bitmap;
                    }

                    if (Cv2.WaitKey(1) >= 0)
                        break;
                }
            }
        }

My drag and drop function:

   private void pictureBox1_DragDrop(object sender, DragEventArgs e)
        {
            int numero = 0;
            numero = listBox1.SelectedIndex;

            var data = e.Data.GetData(DataFormats.StringFormat);
            

            if (data != null)
            {

                string rtsp = listCam[numero].Url;


                if (camera1 == null)
                {
                    camera1 = new Task(() => launchCam(pictureBox1, numero, ts));
                    camera1.Start();
                    activ.Insert(0, 1);

                }
                else
                {
                    if (!camera1.IsCanceled)
                    {

                        
                        try
                        {
                            ts.Cancel();
                        }
                        catch (OperationCanceledException oce)
                        {
                            Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {oce.Message}");
                        }
                        finally
                        {
                            ts.Dispose();
                            System.Diagnostics.Debug.WriteLine("Task {0} status is now {1}", camera1.Id, camera1.Status);
                        }

                    }
                    else
                    {
                        camera1 = new Task(() => launchCam(pictureBox1, numero,ts));
                        camera1.Start();
                    }

                }
            }
            else { Console.WriteLine("ERROR"); }
        }

Upvotes: 0

Views: 121

Answers (1)

JonasH
JonasH

Reputation: 36639

There are multiple issues with the posted code.

  1. Inside the loop you should be calling ts.ThrowIfCancellationRequested() to actually cancel the loop.

  2. A TaskCancellationTokenSource can only be used once. You should cancel the existing object and then create a new one for the next call.

  3. box.Image = bitmap; is run from a background thread. This is just not allowed. Only the UI thread should update the UI. You should ask the UI thread to do this instead, for example by calling Control.BeginInvoke

  4. When the task is canceled, awaiting, waiting, or getting the result of the task will throw OperationCanceledException, not ts.Cancel();. But you are never awaiting or otherwise dealing with the result of the launchCam, and this is a problem. If the method throws an exception, you would never know. I would suggest awaiting the task and show a message box or otherwise log any exceptions other than OperationCanceledException.

I might suggest taking a look at DataFlow instead. that might be able to setup a better pipeline.

Upvotes: 1

Related Questions