How to access and stop a Thread? ASP.NET C#

Asked

Viewed 1,166 times

3

I develop in ASP.NET MVC5 and within a Action of POST I start a Thread:

[HttpPost]
[AutorizacaoFilterAttribute]
public ActionResult ProcessarEmails(ProcessEmailModel model)
{
    ViewBag.Processing = false;

    if (ModelState.IsValid)
    {
        if (EmailAnalisys.State == AnalyseStatus.Stopped || EmailAnalisys.State == AnalyseStatus.Finished)
        {
           Thread thread = new Thread(() => EmailAnalisys.FilterErrorEmails(model.Label, model.Email));
           thread.Start();
            ViewBag.Processing = true ;
         }
     }
     return View(model);

}

How I abort the Thread since I no longer have access to it because I have returned to View ?

Edit: The need to return a View() is because you imagine that the email box has 1000 messages, and I am processing 1 to 1, I need to show the user which message is being processed, type "1/1000" > "2/1000", this is the justification of I need to return the View().

  • In your example if your Thread generates an exception, you will never know. Most correct is to wait for the thread to finish rather than abort it.

  • Here is a reference to how to cancel a task

3 answers

6


Thinking of an answer to the question, and picking up the hook from the discussion with @Perozzo, who has already posted a solution using Thread.Abort, I kept thinking about other ways to abort the thread, things like traffic lights for example, and I came across the interesting article of MVP Joydip Kanjilal: My two cents on the Thread.Abort and Thread.Interrupt methods

In this article, he addresses some aspects of the use of Thread.Abort() and Thread.Interrupt(), and recalls that in the thread we can treat this (detect that it has been aborted), using ThreadAbortException.

In the article he also recalls that neither of the two methods is thread-safe (if you don’t know the concept, you can read more here: Thread Safety), that is, we have to treat the competition to shared resources.

The part that really caught the attention was that he, "in his opinion", did not recommend aborting the thread using Thread.Abort() for example (in free translation):

My honest answer is that you should never use any of these methods to close a thread. It is advisable not to use Thread.Abort methods or Thread.Interrupt to finish one thread - you should instead of this, take advantage of the synchronization objects (such as, Waithandles or Traffic lights) and close "gracefully" the threads that you are using.

Another idea he mentions is to use a variable Boolean volatile shared with the thread, which is verified to continue the implementation of thread and may be amended by another thread, thus ending it in a "graceful" way as he mentions.

An example of the C# Programming Guide:

// variável de controle
internal volatile bool _shouldStop;

// método para "parar a thread", que vai setar a variável
public void RequestStop()
{
   _shouldStop = true;
}

// método da thread
public void DoWork()
{
   while (!_shouldStop)
   {
       Console.WriteLine("worker thread: working...");
   }
   Console.WriteLine("worker thread: terminating gracefully.");
}

Another way to do something similar is by using an object Cancellationtokensource . That piece of code (based In the MSDN) shows an example:

var cts = new CancellationTokenSource();

void ExecutarThread() 
{
    // inicia o token
    cts = new CancellationTokenSource();
    // Passa o token para a thread
    Task.Run(() => DoWork(cts.Token), cts.Token);
}

void CancelarThread()
{
    cts.Cancel();
    cts.Dispose();
}

void DoWork(CancellationToken token)
{
  while (alguma_condicao_de_loop)
  {
     // verifica se foi cancelado
     if (token.IsCancellationRequested) {
        Console.WriteLine("I was canceled while running.");
        // sai e trata
        break;  
        // ou dispara uma exception tratada pelo token
        token.ThrowIfCancellationRequested();
     }
  }
}

The codes are examples adapted to demonstrate functionality, probably need some adjustment to work in each scenario, but are other ways to try to abort a thread.

1

What you’re trying to do is a bad design. Note that, your request is returned without thread completion, but what if the thread generates an exception and does not correctly terminate its operation? How will you know about it if you don’t have a log system, and worse than that, probably already presented a success message to the user.

Aborting a thread can cause many problems, if you abort the thread in the middle of its execution you may get data inconsistency. And since you’ve returned to the main thread, you have no way of knowing if this thread has finished its work.

About all the answers about Thread.Abort(), it is noteworthy that this does not guarantee completion of a thread. When you call the Thread.Abort(), you get Thread one ThreadAbortException, but the same can call the Thread.ResetAbort() and cancel the order.

The right thing is for you to wait for Thread to return:

Thread thread = new Thread(() => EmailAnalisys.FilterErrorEmails(model.Label, model.Email));
thread.Start();
//Se tiver algo para fazer a mais, pode ser feito aqui.
thread.Join();

So your main thread will wait until the thread is finished, and if something goes wrong with the thread I can deal with it effectively (I don’t exemplify in the code how to do this).

Of course, by doing this my code has lost the benefits of using the thread. That’s why I commented on the bad design. To know a good way to work with thread in your case would have to know what FilterErrorEmails implements.

  • I disagree in parts with what you said, because if I wait a Thread execute what advantage I have using this new Thread? being that it needs to be asynchronous as it already is in the action?

  • If I have to wait Thread I just call the method, it’s simpler and cleaner and the same, but I don’t need to call the Thread and return to View

  • You haven’t read my comment completely. As I myself commented has no advantage in doing it the right way, so your code is with bad design.

  • If you don’t want to lock your front-end waiting for a very big process, the most certain is to make a Worker and leave it waiting while the process doesn’t end. Simply ignore the thread and return the value opens your application to failures.

  • imagine that you received a POST , you process the values and need to return to View()(because the user needs an interface to know what is happening), imagine that the POST is a Trigger to run something that NAY can be running 24 hours in the background. How would you do this with a "good design"? because the way I see it (I may be mistaken) there is no "bad design" in my code. It’s just asynchronous programming.

  • you said yourself that you need an interface of what is happening. How will return a result of something that has not yet been finalized?

  • Puts, sorry I didn’t explain right in the question, I’ll edit...

  • Okay, Gabriel, so I need to get back to View()

Show 4 more comments

-1

You can use Thread.Abort. According to your code, thread.Abort();.

But according to a post of Eric Lippert, it’s not certain that this will actually stop the Thread, not to mention that it is risky to use.

Follows:

Let me add that there are no guarantees that call Thread.Abort will actually abort the thread in question. It is possible (but not at all easy) to hinder a thread from being aborted. If for example, you are aborting a thread because you believe it is running hostile code and then hostile code may be resisting its own destruction.

If you have a long code operation that you are not responsible for that needs to be stopped correctly, the correct way to do this is to put the code in your own process, not in your own thread. (And preferably in a highly secure-restricted process). Then you can properly kill the process.

In short, Thread.Abort is the best indicator of bad design, possibly unreliable, and extremely dangerous. It should be avoided at any cost; the only time you should consider aborting a thread is in case of some "emergency shutdown" code where you are trying to shut down a appdomain as cleanly as possible.

  • it is possible to do the Thread.Abort from another thread, as in the example where the controller has already returned the result?

  • Perozzo ok I can use Abort, but as I will have access to that Thread to give the abort?

  • @Ricardopunctual is possible yes, but it is not very easy to do no.

  • @Leonardobonetti because you are wanting to abort the thread?

  • @Perozzo because the thread I give start processes an email box with + 1000 emails, and the need arose to stop it, for example I start again. It’s more to have a control of this thread, because if the email box has 20,000 emails, I would have to wait all this time case, and if I need to stop the process?

  • What if you put this email process inside an Async Task with a timeout? This would be the right way to do what you want.

  • My doubt is the same of @Leonardobonetti, if you can do this in case of his question, because, as far as I know, if you terminate the execution of those who created the thread (in this case, the Controller that has already returned), you "lose" the thread, she keeps running but you can’t get access to her, to do the Abort for example

  • If you abort the thread without finishing it, it will be a problem. Most correct is to wait for the result of it before returning.

  • @Leonardo-Bonetti you would have access to thread if you saved a static variable in the controller (not recommended!), but I believe that the best is to implement one of the solutions proposed by Ricardo Punctual to finish in a more "graceful" way that would make "checks" within your email sending method, you can use Session or the bank to do this semafaro control

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.