-2

As in the title. The functionality I need involves killing a running thread given some conditions. Unfortunately, if the said thread has locked a certain global mutex, that mutex will remain locked forever as I'm using a design where one thread tries to acquire the mutex, but it's only released after doing some work from another thread, which allows another call in the first thread to reacquire it again. Since the first thread is killed, the mutex is never unlocked and the second thread is stuck and unable to do anything about it.

I'd unlock the mutex after the thread is killed (that is, from a new instance of the same thread), but apparently that isn't permitted and results in undefined behaviour, because the mutex has to be unlocked from the same thread that has locked it. What can I do about this? Thanks.

swaggg
  • 460
  • 4
  • 13
  • 4
    *The functionality I need involves killing a running thread given some conditions* Really, really **bad** idea. You have no way to know if the thread is also holding locks that you don't control. – Andrew Henle Oct 26 '21 at 15:59
  • Well, that's precisely the issue. I need to unlock them from outside the thread, after it's killed. – swaggg Oct 26 '21 at 16:00
  • 1
    What about capturing the kill signal in the thread and release the mutex in the handler? – meaning-matters Oct 26 '21 at 16:02
  • 3
    You can't just simply unlock a lock like that. That lock was protecting something from concurrent access, and you think you can just interrupt something like that in the middle of it happening, unlock the lock, and everything is going to work? So when the killed thread was in the middle of a `malloc()` call, with the heap locked, how do you plan on safely killing that thread? You **can't**. – Andrew Henle Oct 26 '21 at 16:04
  • Yes, it was protecting something from concurrent access, but what it was, we shall never know. – swaggg Oct 26 '21 at 16:05
  • You may just need a watchdog thread that detects that the mutex has been locked for too long and terminates the program. It's probably not safe to proceed. – sj95126 Oct 26 '21 at 16:06
  • 1
    @meaning-matters That might work, thanks. – swaggg Oct 26 '21 at 16:09
  • @sj95126 If you control the lock and the resources it's protecting, that's a possible solution. See https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_getrobust.html But that has to be designed in from the start, and the lock must be of a type that can be accessed by another thread when the thread holding the lock is killed. If the lock and whatever it's protecting isn't designed to be killed like that, **you can't safely do it**. If you can even do it at all - the lock may be forever bad after that. – Andrew Henle Oct 26 '21 at 16:22
  • 2
    ...or redesign so that you don't need to terminate/kill any threads until the OS does it at process termination. – Martin James Oct 26 '21 at 16:22
  • 1
    If you can _safely_ kill a thread that locks a mutex, then the mutex serves no purpose in your program. Get rid of it. But, if your program _needs_ the mutex, then you CANNOT safely kill any thread that locks it. The entire point of using a mutex is to prevent other threads from seeing shared data in a temporary inconsistent state when one thread is updating it. If your program kills the thread that is doing the update, then how do you know what state the shared data is in. You _don't_ know, and your program is ****ed. – Solomon Slow Oct 26 '21 at 16:22
  • 2
    No thread should ever force any other thread to do anything (e.g., to die). Threads should _cooperate_ with each other. If thread A needs thread B to die, then thread A should _ask_ thread B to die, and thread B should be designed to promptly respond to the request, and cleanly terminate itself. – Solomon Slow Oct 26 '21 at 16:24
  • This is all interesting input. Actually, it turns out I can unlock the mutex from thread one before it's killed. (It terminates itself rather than being killed from elsewhere). But thanks for your input, everyone. Indeed, what I'd need is a signal handler. – swaggg Oct 26 '21 at 16:27
  • @SolomonSlow, Well it's a bit more complicated than that. Killing the thread prevents the data from being handled. The mutex prevents thread 2 from submitting a request while the previous one is still being processed. But killing thread 1 prevents it from being processed. – swaggg Oct 26 '21 at 16:33
  • @MartinJames Yes, it's not the best design, but was the most convenient. I needed to be able to interrupt a progression and restart it at any point, given some output. – swaggg Oct 26 '21 at 16:54
  • 1
    Does this answer your question? [Is there any way to kill a Thread?](https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread) – Ulrich Eckhardt Oct 26 '21 at 17:02

2 Answers2

1

The functionality I need involves killing a running thread given some conditions.

Threads are an implementation detail. It is not possible to need to kill a thread for functionality unless there's a lot of code you can't control. If you are in that case, the fix is to isolate the thread you can't control into its own process. You can safely kill a process.

Otherwise, you cannot safely kill a thread. But you don't have to. What you need to do is stop the thread from doing the work you don't want it to do and make it do the work that you do want it to do.

You haven't described the work the thread is doing or the threading standard that you are using, so it's not easy to give you advice for the best way to do that. But generally there are two approaches:

  1. Have some shared state that tracks what work needs to be done. Have the code that does work that may need to be stopped check periodically if the work should be stopped.

  2. Use some kind of signaling method to signal the thread doing work that might need to be interrupted that the work it's doing may not need to be done anymore. This avoids the need for periodic checks but generally doesn't avoid the need for shared state.

As a last resort, just implement your own mutex that supports unlocking after thread death. That way, the thread will only hold an instance of this mutex which supports that functionality. In your implementation, there would be an internal boolean protected by an internal mutex that indicates that the mutex is held. That way, when the thread dies, you can just acquire the internal mutex, clear the internal boolean, and release the internal mutex.

Here's how your logic looks:

To lock the mutex:

  1. Acquire the internal mutex.
  2. While the internal boolean is true, wait on the internal condition variable.
  3. Set the internal boolean to true.
  4. Release the internal mutex.

To unlock the mutex:

  1. Acquire the internal mutex.
  2. Set the internal boolean to false.
  3. Broadcast the internal condition variable.
  4. Release the internal mutex.

Now, after thread death, you can just call the "unlock the mutex" operation above. (Make sure any state the mutex protects is consistent first, of course.)

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Thanks for the reply, David. As I mentioned in a comment, the thread actually kills itself. So I misrembered that bit. Otherwise, it's a good point that it's not proper to make routine thread killing a part of your program's core functionality. That said, you must be answering a different question. The question was about how to unlock a mutex after a thread is killed. – swaggg Oct 26 '21 at 18:55
  • 1
    @swaggg My first paragraph addresses that question -- it cannot be done safely. But there's a *very* high chance you can re-architect so that the thread isn't holding the mutex. For example, can you just use a boolean protected by a mutex instead of a mutex? Then you can just acquire the mutex, change the boolean, and release the mutex. (It's not hard to code your own mutex that can be unlocked safely after thread death.) – David Schwartz Oct 26 '21 at 18:56
  • Yes, it would cause undefined behaviour. The question was rather specifically what to do about such a mutex and when to release it and how. Not about whether killing a thread is safe or not. – swaggg Oct 26 '21 at 20:00
  • It's not true it "cannot be done safely" either. That's a generalisation. I've also briefly described what the mutex does, in a comment. But again, that's besides the point, really. – swaggg Oct 26 '21 at 20:34
  • 1
    @swaggg It's a true generalization. For one thing, consider what happens if the thread is killed while it holds some other internal mutex that doesn't have any support for a thread being killed while holding it. – David Schwartz Oct 26 '21 at 21:25
  • Nope, it depends on what's in the thread. – swaggg Oct 27 '21 at 11:19
  • 1
    @swaggg Nope, not true. No matter what you put in the thread, the implementation can implement whatever you put with things like internal mutexes whose state would become corrupt by killing the thread. Unless by "killing" you mean cleanly shutdown, which would be a different question entirely. (Windows is famous for this.) – David Schwartz Oct 27 '21 at 19:20
-1

As @meaning-matters has suggested, this should be possible, at least on Linux, by intercepting the real-time signal 32 and using pthread_cancel, which is implemented using signals.

swaggg
  • 460
  • 4
  • 13