0

I need to stop a Thread when my timer is done.

But this all from a other function.

My Timer starts after Pressing Key: L. a Messagebox appears "Timer started" and my Thread starts too. after 10 seconds, Timer stops with message but my Thread is still running. What can i do? :/

void StartFunction()
{    
    Thread AB = new Thread(SEARCHING) { IsBackground = true };
    AB.Start();

}
void StopFunction()
{
    Thread AB = new Thread(SEARCHING);
    AB.Abort();
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.L)
    {
        StartFunction();
        timer1.Start();
        MessageBox.Show("Timer 1 started!");
    }
}
int time = 0;
private void timer1_Tick(object sender, EventArgs e)
{          
   time++;
   if (time == 10 && timer1.Enabled)
   {
        StopFunction();
        MessageBox.Show("Timer 1 stoped!");
        timer1.Stop();                        
        time = 0;
   }                            
}
ShiiikK
  • 13
  • 6
  • Use of Thread.Abort() is highly discouraged. What's the searching thread actually doing when "SEARCHING"? – 500 - Internal Server Error Mar 18 '22 at 00:10
  • 4
    You basically should NEVER need to `Abort` a Thread. Instead, you simply use some kind of flag (boolean variable) to tell your thread that it should stop whatever it is doing. Your thread can check that flag periodically and then exit itself gracefully. If you want to get fancier, then look at [Cancellation in Managed Threads](https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads). – Idle_Mind Mar 18 '22 at 00:12
  • My Thread SEARCHING is in a while and Look for pixels on screen. And i know this is not a good way but i need this to stop after time from a other function. I have 8 Threads they all are looking for something and if they Found it, they do it… Buf after time, i need a cooldown (rest) or abort. And this all did i need to control from a single function. It is ok if they take few seconds to stop, but how can i make this ? Please dont forget, this thread are started in a other function no on the Same private void – ShiiikK Mar 18 '22 at 00:26
  • 1
    [What's wrong with using Thread.Abort()](https://stackoverflow.com/questions/1559255/whats-wrong-with-using-thread-abort). Be aware that `Thread.Abort()` is not supported in .NET 6. You can use it on the frozen .NET Framework, but not on the actively developed .NET platform. – Theodor Zoulias Mar 18 '22 at 03:03
  • Keep in mind that in your code you create 2 threads, one in `StartFunction` and one in `StopFunction`. – dmedine Mar 18 '22 at 03:24

3 Answers3

1

Idle_Mind is correct on how to accomplish this. Below is a working example using .NET 6.

One important detail is to use Thread.Join(). This will tell your caller to block until the loop is exited and the method returns.

Here I use the command console to key off the switching of the _running flag. You can do the same with a timer or whatever else. Keep in mind that you should probably also implement IDisposable in your class with the thread in it and set _running to false and do the join there as well. That way, you can instantiate the object with using.

namespace Lala
{
    class AB : IDisposable
    {
        private bool _running = false;
        private readonly Thread _thread;

        public AB() => _thread = new Thread(Method);
        private void Method()
        {
            while (_running)
            {
                Console.WriteLine("doing stuff");
                Thread.Sleep(1000);
            }
        }

        public void StartMethod()
        {
            _running = true;
            _thread.Start();
        }

        public void StopMethod()
        {
            _running = false;
            _thread.Join();
        }

        public void Dispose() => StopMethod();

    }
    public class Program
    {
        public static void Main()
        {
            Console.WriteLine("Launching a Thread. Press any key to stop it");
            using AB ab = new(); 
            // AB ab = new(); // if using is not appropriate
            ab.StartMethod();
            while (!Console.KeyAvailable)
                Thread.Sleep(10);
            // ab.StopMethod();// if using is not appropriate
        }
    }
}
dmedine
  • 1,430
  • 8
  • 25
  • 1
    `_running` should at least be volatile, otherwise it is possible for the loop to never exit if it can keep the variable in a register. But I would probably recommend using a cancellationToken instead. – JonasH Mar 18 '22 at 07:54
  • ye but iam using .NET 7.3. are there any idea how to bring a Thread there slowly to stop after few seconds? – ShiiikK Mar 18 '22 at 08:18
  • @Shiiikk the latest .net is 6. I assume you mean c# 7.3. And you do not control how quickly threads run, unless you insert sleeps. – JonasH Mar 18 '22 at 08:27
  • But then how can i stop a Thread from a my "void StopFunction(){}"? I think it can't be that difficult to make it possible somehow? i need to shutdown all Thread at the same time so in this void i have then 11 Threads. – ShiiikK Mar 18 '22 at 08:34
  • @Shiikk this example shows you how to stop threads! Set a variable that is checked periodically by each thread, and make the threads exit when the variable is set. And it should be trivial to modify to process 11 threads instead of 1. – JonasH Mar 18 '22 at 08:40
  • Thanks but i cannot use this. This code is for C# 7.3.. i work with 8.0 and on this version this code is not working anymore? On this line " Console.WriteLine("Launching a Thread. Press any key to stop it"); using AB ab = new();" my IDE says to me i cannot use this for C# 8 or higher – ShiiikK Mar 18 '22 at 18:41
  • @ShiiikK, I think you are misreading your error messages. `using AB = new();` is valid in C#>= 9.0. `using` came in with v8, and target typed object creation is #>=9.0. This is compiled with C# 10. Trust me, it works. – dmedine Mar 20 '22 at 23:48
0

Using modern methods you would write something like

private async void Form1_KeyDown(object sender, KeyEventArgs e)
{
    var cts = new CancellationTokenSource(10000);
    var task = Task.Run(() => Search(cts.Token));
    try
    {
        var result = await task;
        // handle result
    }
    catch (OperationCanceledException)
    {
        // handle cancelled
    }
    catch (Exception)
    {
        // handle other exceptions
    }
}

public int Search(CancellationToken cancel)
{
    while (true)
    {
        cancel.ThrowIfCancellationRequested();
        // Do searching
        if (found)
            return result;
    }
}

This would use thread pool threads instead of dedicated threads, and avoids the need to manually managing a timer. It also makes it easy to handle the result from the operation, if there are any.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • ok maybe there is a other way. is it possible to stop a loop and continue later? because with threads it dont work. – ShiiikK Mar 18 '22 at 09:13
  • @Shiikk Such things are possible, but it really depends on the details about what you are trying to accomplish. My go to solution is a progress-dialog with a cancel button, messing around with timeouts etc seem fairly odd to me. – JonasH Mar 18 '22 at 09:39
  • Yeah. This is another way to do it. However, I am constantly being told that I should only use the async pattern with things that are truly asynchronous, not just for concurrency. Of course, I do it all the time anyway... – dmedine Mar 20 '22 at 09:53
  • @dmedine The important things is to know what tools are available and when each is appropriate. I think the recommendation comes from new developers seeing async and tries to apply it where there are better tools available. Using async/await to wait for some background work should be perfectly fine, since the alternative would be much more cumbersome and complex to write. – JonasH Mar 21 '22 at 07:05
  • can you explain your code? i understand now why it is better not to use my option. i opened a new Post here, https://stackoverflow.com/questions/71562043/how-can-i-make-multiple-async-await-tasks-windows-forms I would be very grateful if you could bring this closer to me – ShiiikK Mar 21 '22 at 18:20
0

Unfortunately, everything posted before didn't work for me or i just had not understand what i have to do.

Iam a C# Novice and I have a hard time understanding technical terms.

But i found a solution to make this possible.

This stops not the Thread but it Stops the while there has a function in a Thread.

First set a bool on top under public partial class:

    public partial class Form1 : Form
    {
       private volatile bool m_StopThread;

then you have to give your while in the function this:

while (!m_StopThread)

this means that your while is still not running until this is set true.

After this is set, you give your Button or Timer a function maybe like this:

        if ()
        {
            m_StopThread = true;
                            
        }

If this function is active your Thread will Start, because now its true and not longer false.

at the same way you can stop this again by set this function to false again.

If the solution I'm explaining has already been suggested, I thank you. And hope it helps others. But unfortunately I couldn't understand how to proceed now.

Thank you to those who go out of their way to help people like me every day. :)

ShiiikK
  • 13
  • 6