6

Here's the situation, I am writing the framework for a code war contest. As the code runs, for each turn, it calls a method in the library provided by each contestant. The rules of the contest is the method must return in 1 second or we kill the task calling them. We then use a default result for that turn.

The method has no support for a cancel because we cannot trust the called code to respond to a cancel. And we need to kill the thread because if we have 10 or 20 ignored background tasks then all calls going forward will provide fewer clock cycles on each call and methods that before took less than 1 second now take more.

On the plus side, the method we're killing should have no resources open, etc. so an abort should not leave anything hanging.

Update: Two things to keep in mind here. First, this is like a game - so performance is important. Second, the worker thread is unlikely to have any resources open. If one of the called methods goes overlong, I need to abort it and move on quickly.

David Thielen
  • 28,723
  • 34
  • 119
  • 193
  • 4
    You can't kill Threads or Tasks (and expect to keep a stable app). – H H Aug 13 '11 at 20:25
  • possible duplicate of [Timeout Pattern - How bad is Thread.Abort really?](http://stackoverflow.com/questions/710070/timeout-pattern-how-bad-is-thread-abort-really) – H H Aug 13 '11 at 20:26
  • 3
    I'll agree it's a bad idea. Unfortunately in the real world sometimes we have to implement the least bad idea when there is no good solution. For this case what do you suggest? – David Thielen Aug 13 '11 at 20:32
  • 2
    The standard answer is to launch the code in a separate Process or AppDomain. Asked and answered many timers here, the dupe I linked too isn't the best. – H H Aug 13 '11 at 20:48
  • Dave, welcome to [SO]. You'll find we strongly discourage the use of signatures. – John Saunders Aug 13 '11 at 21:55
  • Also, be aware that C# has no support for tasks. Such support is present in the .NET Framework, which can be used by any .NET application. – John Saunders Aug 13 '11 at 21:56
  • 2
    John - My mom taught me to say thank you when asking a favor. I'm afraid mom overrules everything so I sign with thanks and my first name when I ask questions. – David Thielen Aug 13 '11 at 23:01
  • With all respect to your mother, see [Should 'Hi', 'thanks,' taglines, and salutations be removed from posts?](http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be-removed-from-posts/). – John Saunders Aug 14 '11 at 00:19
  • 1
    John - interesting discussion. I definitely agree with the minority there that a thank you is fine. As it's discouraged but not forbidden I'm going to keep doing it. – David Thielen Aug 14 '11 at 15:11
  • @DavidThielen: [this post](http://social.msdn.microsoft.com/Forums/vstudio/en-US/d0bcb415-fb1e-42e4-90f8-c43a088537fb/aborting-a-long-running-task-in-tpl?forum=parallelextensions) probably contains exactly what you need – starteleport Oct 11 '13 at 06:22

3 Answers3

2

You should run each contestant in his own AppDomain with low privileges. This has several advantages:

  1. It's sandboxed
  2. It can't interact with any other code in the process
  3. Force unloading an AppDomain is relatively clean.

Even if you prefer killing the thread over unloading the AppDomain I'd still put each contestant into an AppDomain to get the isolation.

Unfortunately Thread.Abort is not enough. It still executes finally clauses which can take as long as they want.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • The app domain is an interesting idea. I would still just abort rather than re-load it if it times out for performance reasons. I don't think they will have finally clauses - the issue is not they will purposely choose to do something bad, just that their code will take a long time to run. Thankss – David Thielen Aug 14 '11 at 00:43
1

I would recommend that you run the code in a second process and carefully define the interface for communicating with it to ensure that it can handle not receiving a response. Most operating systems are designed to clean up fairly well after a killing a process.

For communication, you should probably avoid .NET remoting, as that seems likely to be left in an inconsistent state on the server side. Some other choices: sockets, named pipes, web service.

Dark Falcon
  • 43,592
  • 5
  • 83
  • 98
  • "sockets, named pipes, web service" - use WCF. It is (more or less) the official replacement for .Net Remoting, and supports all of these bindings. – Merlyn Morgan-Graham Aug 13 '11 at 20:51
  • 1
    This is typically the best way to do this, sandboxing like Chrome. However, I'm guessing it will be nearly impossible to force the 1 second timeout with the overhead of starting a whole new process each time. The goal seems to be something like "best run time wins", which would be problematic here. – drharris Aug 13 '11 at 20:52
  • Yep, the overhead of this would be significant for this case. – David Thielen Aug 13 '11 at 23:01
  • You can probably design this to only kill the process if the timeout is actually exceeded. This should reduce the overhead of the separate process. – Dark Falcon Aug 15 '11 at 00:57
1

Thread.Interrupt() method is maybe what you are looking for.

As the MSDN documentation says, "If this thread is not currently blocked in a wait, sleep, or join state, it will be interrupted when it next begins to block."

It is not an abort, it forces the running thread to throws ThreadInterruptedException when the thread enters in a wait state.

You can then use a timer in another thread with a timeout to check if the thread don't really want to terminate, if the thread refuses to terminate in, for example, 30 seconds, you can abort it.

Salvatore Previti
  • 8,956
  • 31
  • 37
  • I can't do the 30 second wait every time a response goes over-long. That could turn a 1 minute run of the contest into hours. I think I need to go straight to abort. – David Thielen Aug 13 '11 at 23:02