recv() is not interrupted by a signal in multithreaded environment

参见:http://stackoverflow.com/questions/3582226/recv-is-not-interrupted-by-a-signal-in-multithreaded-environment

在写多线程程序时,我也遇到了与下面这位哥们一样的情况:

I have a thread that sits in a blocking recv() loop and I want to terminate (assume this can't be changed to select() or any other asynchronous approach).

I also have a signal handler that catches SIGINT and theoretically it should make recv() return with error and errno set to EINTR.

But it doesn't, which I assume has something to do with the fact that the application is multi-threaded. There is also another thread, which is meanwhile waiting on a pthread_join() call.

What's happening here?

EDIT:

OK, now I explicitly deliver the signal to all blocking recv() threads via pthread_kill() from the main thread (which results in the same global SIGINT signal handler installed, though multiple invocations are benign). But recv() call is still not unblocked.

EDIT:

I've written a code sample that reproduces the problem.

  1. Main thread connects a socket to a misbehaving remote host that won't let the connection go.

  2. All signals blocked.

  3. Read thread thread is started.

  4. Main unblocks and installs handler for SIGINT.

  5. Read thread unblocks and installs handler for SIGUSR1.

  6. Main thread's signal handler sends a SIGUSR1 to the read thread.

Interestingly, if I replace recv() with sleep() it is interrupted just fine.

PS

Alternatively you can just open a UDP socket instead of using a server.

他给了源代码,我这儿就省了。

最重要的这个回答很全面,值得参考:

Normally signals do not interrupt system calls with EINTR. Historically there were two possible signal delivery behaviors: the BSD syscalls are automatically restarted when interrupted by a signal) and the Unix System V syscalls return -1 with errno set to EINTR when interrupted by a signal). Linux (the kernel) adopted the latter, but the GNU C library developers (correctly) deemed the BSD behavior to be much more sane, and so on modern Linux systems, calling signal (which is a library function) results in the BSD behavior.

POSIX allows either behavior, so it's advisable to always use sigaction where you can choose to set the SA_RESTART flag or omit it depending on the behavior you want. See the documentation for sigaction here:

http://www.opengroup.org/onlinepubs/9699919799/functions/sigaction.html

你可能感兴趣的:(sigaction,Signal,recv)