3

If I have an app that is creating threads which do their work and then exit, and one or more threads get themselves into a deadlock (possibly through no fault of my own!), is there a way of programmatically forcing one of the threads to advance past the WaitForSingleObject it might be stuck at, and thus resolving the deadlock?

I don't necessarily want to terminate the thread, I just want to have it move on (and thus allow the threads to exit "gracefully".

(yes, I know this sounds like a duplicate of my earlier question Delphi 2006 - What's the best way to gracefully kill a thread and still have the OnTerminate handler fire?, but the situation is slightly different - what I'm asking here is whether it is possible to make a WaitForSingleObject (Handle, INFINTE) behave like a WaitForSingleObject (Handle, ItCantPossiblyBeWorkingProperlyAfterThisLong)).

Please be gentle with me.

* MORE INFO *

The problem is not necessarily in code I have the source to. The actual situation is a serial COM port library (AsyncFree) that is thread based. When the port is USB-based, the library seems to have a deadlock between two of the threads it creates on closing the port. I've already discussed this at length in this forum. I did recode one of the WaitForSingleObject calls to not be infinite, and that cured that deadlock, but then another one appeared later in the thread shutdown sequence, this time in the Delphi TThread.Destroy routine.

So my rationale for this is simple: when my threads deadlock, I fix the code if I can. If I can't, or one appears that I don't know about, I just want the thread to finish. I doesn't have to be pretty. I can't afford to have my app choke.

Community
  • 1
  • 1
rossmcm
  • 5,493
  • 10
  • 55
  • 118
  • 3
    Why don't you just change the `WaitForSingleObject` call to *not* be infinite? – Jon Skeet Dec 18 '11 at 13:22
  • 6
    Fix the deadlock. Fix the disease. – David Heffernan Dec 18 '11 at 13:23
  • I can not figure out a situation where the thread runs into a deadlock and you can force it to "move on" with other code outside the deadlock and thus exit "gracefully". Im my opinion you have to avoid the deadlock, thats the only possibility... – Andreas Dec 18 '11 at 13:24
  • @Jon Whilst that would make the wait return, it would hardly solve the problem. – David Heffernan Dec 18 '11 at 13:24
  • @DavidHeffernan: Indeed, fixing the deadlock would certainly be a better option. It was really just a response to the "how do I make it act as if I'd passed in a timeout" part - where the obvious answer is to pass in a timeout :) It's hard to really give a good answer without knowing more context here... – Jon Skeet Dec 18 '11 at 13:30
  • 1
    @Jon, deadlocks are the easiest multithreading issue to solve. Once there is a proper threadstack it becomes trivial, provided one has control over the source code. – bestsss Dec 18 '11 at 18:43
  • From your edit it would appear that you do have the source code. I urge you to solve the deadlock. – David Heffernan Dec 18 '11 at 18:46
  • @David, I do intend to solve it. What I want is a fallback when one occurs that I don't know about. For me, it's much the same philosophy as having exception handling in my apps. It's there for the run-time errors I don't know about. The ones I _do_ know about don't happen any more (hopefully). – rossmcm Dec 18 '11 at 19:46
  • In my view there is no fallback. Deadlock is game over. – David Heffernan Dec 18 '11 at 19:48
  • @bestsss: It depends on whether the deadlock is a *real* deadlock, or whether that's actually being used as a shorthand here for "something's not finishing and I don't know why". – Jon Skeet Dec 18 '11 at 20:27
  • @Jon, According to my reading of the trace stacks, it's a deadlock. – rossmcm Dec 18 '11 at 20:34

2 Answers2

5

You can make a handle used in WaitForSingleObject invalid by closing it (from some other thread). In this case WaitForSingleObject should return WAIT_FAILED and your thread will be 'moved on'

kludg
  • 27,213
  • 5
  • 67
  • 118
4

If you don't use INFINITE but just set a given timeout time, you can check if the call returned because the time out time expired or because the handle you were waiting for got into the signalled state. Then your code can decide what to do next. Enter another waiting cycle, or simply exit anyway maybe showing somewhere 'hey, I was waiting but it was too long and I terminated anyway). Another options is to use WaitForMultipleObjects and use something alike an event to have the wait terminate if needed. The advantage it doesn't need the timeout to expire. Of course one the thread is awaken it must be able to handle the "exceptional" condition of continuing even if the "main" handle it was waiting for didn't return in time.