6

Say I have a thread that's something like this:

void my_thread(char *device_name) {
    int fd = open(device_name, O_RDONLY);
    struct input_event ev;

    while(1) {
        read(fd, &ev, sizeof(struct input_event));
        /* do something */
    }
}

How do I stop such a thread? One way is using pthread_cancel, but I'd rather do it more gracefully. Something like pthread_kill perhaps? In such case, however, would the read method unblock (as I presume it should) and how would the thread handle the signal? Or is it the process that should handle it?

I'd be very grateful for an advice!

Albus Dumbledore
  • 12,368
  • 23
  • 64
  • 105
  • Can you design your app so that killing these kinds of thread is not necessary? That dodges the problem of killing it off. Can you not just leave this thread alone until the app exits and the OS destroys all threads? If the device is dead, then there's not much you can do about it :( – Martin James Jun 14 '11 at 14:20

3 Answers3

6

You problem is actually "how to interrupt blocking system call from other thread".

Try searching for it. Here is one of the similar discussions: Proper way to close a blocking UDP socket

Community
  • 1
  • 1
blaze
  • 4,326
  • 18
  • 23
  • 1
    Closing a socket handle from another thread works OK on Windows - unblocks the call. Closing a socket handle from another thread works OK on Linux - unblocks the call. In the particular case of a blocking call on a UDP socket, (as in the link), what's wrong with sending a UDP message to the port locally to persuade the call to return? The thread could then realize it had to die and terminate itself. – Martin James Jun 14 '11 at 14:29
  • It can be done with UDP if you don't mind following: a) keeping UDP socket unbound, otherwise you can't send to it; b) creating new socket during shutdown; c) losing real data packets which came in exactly same moment as your "unblock" packet: there is no guaranteed way to distinguish between "read" and "fake" packets. As for "works OK" - it was pretty nasty surprise for me when FreeBSD upgrade broke my app exactly because close() worked OK before and stuck forever after. – blaze Jun 15 '11 at 08:35
5

The answer to this is to not do anything that will block without a timeout. For IO, you shouldn't call read() until you know the call will not block. For example, use poll() or select() on the path first in order to determine the status.

mah
  • 39,056
  • 9
  • 76
  • 93
  • That doesn't really answer the question, though. What if you have a blocking call with a really long timeout? – Oliver Charlesworth Jun 14 '11 at 10:41
  • 2
    Yes, but ... don't. Avoid blocking calls like the plague. Coding with blocking calls is like using punch cards. It's batch oriented. – Prof. Falken Jun 14 '11 at 10:49
  • @Oli -- it _does_ answer the question: don't do it. If you block in the kernel, you cannot terminate your thread except through the grace of whatever kernel code you're blocked in. Sending a signal might unblock you and it might not, and it can depend on which signal (and SIGKILL is not guaranteed to be special while you're within kernel code). Thus to paraphrase the movie War Games, the only way to win is to not play. – mah Jun 14 '11 at 11:03
  • 1
    @mah: Maybe I'm missing something! Let's assume we have a worker thread to handle e.g. network I/O. How do you propose to have this thread idle-wait on input without some kind of blocking mechanism? (AFAIK, `select` also blocks for the duration of the timeout, or until an input becomes ready.) – Oliver Charlesworth Jun 14 '11 at 11:19
  • @Oli - yes, select() blocks briefly, however its controlled in that you get the luxury of bounding the block time... read() is infinite. By using select, you move from an impossible-to-solve problem to a tradeoff of response time vs. CPU overhead. Once the thread is again controllable, convincing it to stop gracefully is not difficult -- signals can be responded to (where they could not be if the thread were endlessly blocked), condition variables can be examined, etc. – mah Jun 14 '11 at 11:23
  • 1
    @mah: setsockopt(SO_RCVTIMEO) makes recv() return if no data received for some time. Just like select() but without select(). – blaze Jun 14 '11 at 11:55
  • @mah: I largely agree with that. But I think that leads to a more elaborate answer, which is e.g. use `select` with a file-like communication mechanism, which avoids having to choose between reponsiveness and overhead. – Oliver Charlesworth Jun 14 '11 at 13:06
  • Best example of this is a NFS server outage under some mount options. Back in the day, many operations would hang indefinitely, wothout any way to kill them. I think there have been some changes to this, but still... – ninjalj Jun 14 '11 at 22:22
0

You can't kill a thread gracefully. If you want clean exit, make sure the thread exits based on some condition.

Coder
  • 3,695
  • 7
  • 27
  • 42
  • In your case add while(bExitThread), where bExitThread is volatile variable that can be changed from another thread. – Coder Jun 14 '11 at 11:15
  • That's obvious. I'm troubled about the blocking `read` function. – Albus Dumbledore Jun 14 '11 at 11:21
  • If he's blocked in a read() call which will not unblock for a long time (if ever), it will be difficult for him to read that condition variable. What you're saying is correct but secondary to not blocking uncontrollably in the first place. – mah Jun 14 '11 at 11:25
  • Try using IO completion ports or something like that? Just leak the thread if it will exit in sane amount of time anyway? Hard to say without more information about architecture. – Coder Jun 14 '11 at 11:26