views:

211

answers:

2

I have to use an API to make a call to a third party, and ideally use the response it returns. The API has a built-in 30 second timeout, and does not allow you to set that programatically. I need it to time out in 12 seconds. Here's the call I'm making:

string response = theAPI.FunctionA(a, b, c, d);

I've been thinking I might need to use async calls to accomplish this and abort the thread at 12 seconds. Another stackoverflow question appears to come close to what I'm considering: http://stackoverflow.com/questions/299198/implement-c-generic-timeout

...I'm just wondering if this is the best way. Specifically, I keep seeing articles that warn you to call EndInvoke no matter what, and I'm wondering if Abort as in the referenced example will still close the thread appropriately? I see there were some comments with much concern about using Abort.

+4  A: 

Aborting threads is generally a bad idea. Why not just let the call complete (or time out after 30 seconds) but ignore the result (and move on) if it takes more than 12 seconds?

Jon Skeet
The deal is at 12 seconds I need to bail out and move on. I can't sit and wait for the full 30 seconds. If I was allowed to let it run the full 30 seconds I would go that way certainly.
Chad
I wasn't suggesting waiting for 30 seconds. Note the "ignore the result (and move on) if it takes more than 12 seconds" bit. All I'm suggesting is that your timeout shouldn't actually kill the request. Let it complete naturally, while you get on with other stuff.
Jon Skeet
Ok I think I follow you. I would maybe do an async call with a callback function waiting there for things to finish. Meanwhile my code moves on, and if I don't have a response yet after 12 seconds I proceed as if there was a timeout. My callback function just does nothing if over 12 seconds.
Chad
Yes, something like that :) Just a BeginInvoke/WaitOne(timeout)/EndInvoke may be okay, with a callback calling EndInvoke in case the main thread doesn't. You'd have to check that calling EndInvoke multiple times is okay though - I don't know offhand.
Jon Skeet
+1  A: 

Thread.Abort will close the thread, of course, as it will call Win32 TerminateThread.

Outcome of this action will depend on how your API likes to be closed by TerminateThread.

If your method is called somthing like NuclearPlant.MoveRod() or Defibrillator.Shock(), I'd rather wait these 30 seconds.

This method gives no chance to the victim to do some cleanup:

TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code. DLLs attached to the thread are not notified that the thread is terminating. The system frees the thread's initial stack.

As stated in MSDN:

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

  • If the target thread owns a critical section, the critical section will not be released.
  • If the target thread is allocating memory from the heap, the heap lock will not be released.
  • If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
  • If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
Quassnoi
Sounds like you don't feel doing an Abort is a safe idea, and I can see why by your comments. So if Abort is something to be avoided, do you have an alternative solution?
Chad
If you API has no way to stop the method, there is no alternative solution. All such solutions, if any, rely on thread's ability to react to the external signals and act appropriately. If the thread does not do it, TerminateThread is the only way to stop it.
Quassnoi