0

I am in a bottleneck finishing a GUI in Windows Forms C#. I am 100% new doing this and I think that I am mixing and messing around. Someone could help me please?

I am embedding an artificial vision application (developed in HALCON software and exported to C#). I resume this app in one class with one method having three outputs (couple of images and a string).

I put this class inside a while loop with other classes to iterate and interact with the outputs from the vision app till state statusFile is 1 to exit the loop.

Firstly I was using only the mean thread and my GUI got unresponsive when inside the while loop was getting into the vision.

Snippet of Start button:

public string pathFile { get; set; } // THIS DATA COMES FROM PREVIOUS WFORM
public DataTable dataLonas { get; set; }
public string namePro { get; set; }

public Thread Run_thread = null, run1 = null;
public static AutoResetEvent myResetEvent
    = new AutoResetEvent(false); // initially set to false.

public VentanaIniciarProceso3()
{
    InitializeComponent();
}

private void button_start_process_Click(object sender, EventArgs e)
{

    string name_button = button_start_process.Text;

    if (name_button == "Start")
    {

        boton_iniciar_proceso1.Text = "Pause"; // CHANGE THE LABEL
                                               // instead having more buttons

        run1 = new Thread(t => //HERE THE NEW THREAD
        {
            while (statusFile == 0) //
            {

                HObject ho_IMAGE_OPERARIOS = null;
                HObject ho_ActualImageTrim = null;
                HTuple hv_READ_OCR_STRING = new HTuple();

                // HALCON CLASS
                (hv_READ_OCR_STRING, ho_ActualImageTrim, ho_IMAGE_OPERARIOS) =
                    LONASapp.action(hv_AcqHandle, hv_AcqHandle_2, pathFile, namePro);

                string codigo = hv_READ_OCR_STRING.ToString();

                // EVAL CODE
                int aux_aviso = EvalCodigoBeta.analizarAvisoBeta(codigo,
                    dataLonas, pathFile, namePro);

                // EVAL FILE CLASSFICHERO.
                // statusFichero para 1 o 0
                // Variable que indique si fuerza operario
                statusFile = EvalFichero.checkCarga(dataLonas, pathFile, namePro);
                statusFile = ContinuarSalirProyecto.continuarSalir(statusFile);

                // IF statusFile==1 It Will exit 
            }
        })
        { IsBackground = true };

        run1.Start(); // START IN BACKGROUND THE LOOP WITH THE CLASSES
    }
    else if (name_button == "Pause")
    {
        myResetEvent.WaitOne(); // SAME BUTTON WITH LABEL CHANGED TRYING
                                // TO PAUSE THE THREAD
        boton_iniciar_proceso1.Text = "Resume";
    }
    else
    {
        myResetEvent.Set(); // SAME BUTTON WITH LABEL CHANGED
                            // TO "RESUME" TO UNPAUSE
        boton_iniciar_proceso1.Text = "Pause";
    }
}

After doing this change, the GUI gets responsive which is nice and the correct way I am sure is using different threads. But when clicking again to the button which has changed the label to "Pause", it does not pause the thread run1, it continues… and now the GUI gets paused/unresponsive when cause of myResetEvent.WaitOne();

Could I ask you for help please? I am confused also and do not know where to continue or what to change…

Thanks a lot in advance. I really want to close this thing after 5 days not coming with the good idea.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Erik Martinez
  • 23
  • 1
  • 4
  • 1
    The [`AutoResetEvent`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.autoresetevent) is a low level synchronization primitive. An application developer should rarely have a need for it, if ever. Nowadays even threads are considered low level, since we have [tasks](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap) and [async/await](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/). – Theodor Zoulias Mar 23 '20 at 10:29
  • Thanks Theodor !! So I could use Task.Run(() => { }); Instead of run1 = new Thread(t =>{ }); Would it be posible to pause the whole task? In a simple way? Gonna have a look at it – Erik Martinez Mar 23 '20 at 11:22
  • 2
    Yes, the standard practice for canceling a `Task` is by passing a `CancellationToken` to it, which you control by an associated [`CancellationTokenSource`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.cancellationtokensource). You can cancel multiple tasks at once by cancelling a single `CancellationToken`. You can read an overview of cancellation [here](https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap#cancellation-optional). – Theodor Zoulias Mar 23 '20 at 12:07
  • 1
    By your implementaion, check if your task is finished yet in the beginning. If it's running, return it. If not, execute your task suggested by @TheodorZoulias. – Louis Go Mar 23 '20 at 12:10
  • I swap the code for the, adding a token to it. -CancellationTokenSource source1 = new CancellationTokenSource(); -CancellationToken token1 = source1.Token; -Task.Run(() => {..}, token) and when click Pause button source1.Cancel(); but nothing happened. i ask if the task CanBeCanceled and it gives true. And after ask do source1.Cancel(). I ask again if cancelation is requested. Gives me also true.. Doesnt stop at any part :( – Erik Martinez Mar 23 '20 at 15:44
  • 1
    You should call the method [`CancellationToken.ThrowIfCancellationRequested`](https://docs.microsoft.com/en-us/dotnet/api/system.threading.cancellationtoken.throwifcancellationrequested) periodically inside your task. The `cancellationToken` parameter of `Task.Run` is there just for the period between scheduling and starting the task. After the task has started running, there is no way to stop it from the outside, other than aborting the thread, which is a no-no. So you must query the token periodically from the inside, and throw an `OperationCanceledException` to signal the cancellation. – Theodor Zoulias Mar 24 '20 at 06:04
  • Thanks Theodor for being more specific!! Yesterday could do something using: manual reset events, adding ,as you mentioned, inside the thread waitHandle.WaitOne(); and rest of buttons with waitHandle.Reset(); and waitHandle.Set(); To Pause and resume... It´s not perfect.. but somehow works.. Gonna try with your last comment since you are expert on this and probably the Task/CancellationToken is optimized already- Will update the post - thanks again! – Erik Martinez Mar 24 '20 at 17:11

0 Answers0