4

I have this code

        Thread thread1 = new Thread(this.DoSomething1);
        Thread thread2 = new Thread(this.DoSomething2);
        thread1.Start();
        thread2.Start();

I need the first thread that finishes to kill the other immediately. Note that the thread is not the kind that runs a while look so I can not use a static variable telling the thread to stop. Which thread will end first?

Kit
  • 20,354
  • 4
  • 60
  • 103
Udi Aslan
  • 148
  • 3
  • 9
  • 2
    There's no safe way to kill a thread. As for waiting for one of the tasks to finish, just use `Task.Run` instead of creating manual threads, and you can use `Task.WhenAny`. – Luaan Jul 10 '15 at 16:09
  • 1
    This sounds somewhat of an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). What are your threads actually doing that you need them to behave in this fashion? – James Thorpe Jul 10 '15 at 16:24
  • Guys, thanks for the quick response but: 1. My threads don't loop. 2. They do totally different jobs. – Udi Aslan Jul 10 '15 at 16:57
  • // try this [http://stackoverflow.com/questions/3071302/stopping-work-from-one-thread-using-another-thread][1] [1]: http://stackoverflow.com/questions/3071302/stopping-work-from-one-thread-using-another-thread – Bhavin Jul 14 '15 at 10:42

4 Answers4

4

Ideally you'd want to use a cancellation token or static variable to cancel the thread safely.


If you decide to use the cancellationToken/tokenSource:

  var tokenSource = new CancellationTokenSource();
  var token = tokenSource.Token;

  ...

  static void DoSomething1or2(CancellationToken token, CancellationTokenSource tokenSource)
  {

      //Do other work here

      //Since you said neither of your tasks were looping, just put this where
      //you'd want to cancel the thread
      if(token.IsCancellationRequested)
        return; // or token.ThrowIfCancellationRequested();

      //do some more stuff here

      tokenSource.IsCancellationRequested = true;
  }

If your doSomething method is looping then you could check a boolean at the beginning or end of each loop to see whether the other thread is completed. This technique is fairly similar to the cancellationToken.

if(otherThreadIsActive && originalCondition)
   {
       //do stuff here
   }

If you can't wait for that iteration to finish, or can't use cancellation token, then I'd suggest reading this thread on aborting. Best not to use it unless it's absolutely necessary.


Best way: use a cancellation token/tokenSource

Next best way: use some sort of boolean to dictate when to terminate

Community
  • 1
  • 1
Speerian
  • 1,138
  • 1
  • 12
  • 29
  • This is - for the most part - the way to go. You should remove the abort part, not because it's technically wrong but because it's not correct for the (rather trivial) example the OP posted. I don't see any exceptional circumstance in the OP's code that would warrant aborting the other thread (how do you even know which thread gets aborted - one doesn't even know which starts first and there's no guarantee that aborting will happen when you issue the command). I'll upvote your answer if you remove the abort part. – xxbbcc Jul 10 '15 at 18:13
  • @xxbbcc I'll emphasize that he really should not use the thread.Abort(), but I don't want to remove it. Better people know about it, and not to use it, than be ignorant of it. – Speerian Jul 10 '15 at 18:34
  • I agree with you on that detail, so +1 – xxbbcc Jul 10 '15 at 19:33
2

Thread is for ‘fire and forget’ threads that you start and never interact with again. If you need to interact with a thread, such as to stop it after it has started, or if you need to know when a thread has finished, you should use Task.Run and not Thread. If you want to cancel a Task while it is still running you need a CancellationTokenSource.

var cts = new []
{
    new CancellationTokenSource(),
    new CancellationTokenSource()
};
var ts = new[]
{
    Task.Run(() => DoSomething1(cts[0].Token), cts[0].Token),
    Task.Run(() => DoSomething2(cts[1].Token), cts[1].Token)
};

var w = Task.WaitAny(ts);
for (int i = 0; i < cts.Length; i++)
{
    if (i != w) cts[i].Cancel();
}

Your DoSomethings will have to monitor CancellationToken.IsCancellationRequested to cancel and perform cleanup. You need to pass the token to Task.Run to detect if the thread threw an exception, I have not shown that. For more information consult How to Cancel a Task and Its Children.

Dour High Arch
  • 21,513
  • 29
  • 75
  • 90
0

It is very important what are you doing in those threads. If there is a for loop in both you can stop a thread by reading a shared variable in the beggining of the loop or anywhere in the loop body. If it's just heavy computing (a complex business flow or a complex mathematical thing) it is even dangerous to kill a thread in the middle of something.

George Lica
  • 1,798
  • 1
  • 12
  • 23
  • It is _always_ dangerous to kill a thread. It should always exit cooperatively by responding to a synchronization primitive. – xxbbcc Jul 10 '15 at 16:21
0

What I've done in the past when dealing with syncing thread cancellations is have have a static event in the class that spins up the threads. These threads execute functions of different classes that all listen for this static event to be fired. When this event fires, a volatile private bool _aboutRequested is set to true that is found within the spun up threads execution class. During the thread execution loop, the last thing done is checking this exit requested bool, and if true, gracefully exit.

xtreampb
  • 528
  • 6
  • 19