How to wakeup Select call without timeout period from another thread
Thanks all for valuable suggestion, I am able to resolve the issue with shutdown() call on socket FD using reference answer present on this link, it will pass wakeup signal to select, which is waiting for action. We should close socket only after select call otherwise select will not able to get wake up signal.
select() on half-open socket does not return on close()?
Yes you misuse the select
. The man select
states:
If a file descriptor being monitored by select() is closed in another thread, the result is unspecified. On some UNIX systems, select() unblocks and returns, with an indication that the file descriptor is ready (a subsequent I/O operation will likely fail with an error, unless another the file descriptor reopened between the time select() returned and the I/O operations was performed). On Linux (and some other systems), closing the file descriptor in another thread has no effect on select(). In summary, any application that relies on a particular behavior in this scenario must be considered buggy.
So you cannot close connection from other thread. Unfortunately the poll
has the same issue.
EDIT
There are several possible solution and I have not sufficient information about your application. Following changed can be considered:
- Use
epoll
instead ofselect
if you are on linux or other modern polling mechanism if you on another OS.select
is quite old function and it was designed in time when threading was not considered seriously. - Establish a communication channel between the select thread and the keep-alive thread. When keep alive thread detects a dead peer then don't close the socket itself but instructs the select thread to do that. Typically it can be done through a local socket. The local socket is added to select descriptor set and when the keep-alive thread writes something to it the select thread wakes up and can take an action.
how to wakeup select() within timeout from another thread
I use an event object based on pipe()
:
IoEvent.h:
#pragma once
class IoEvent {
protected:
int m_pipe[2];
bool m_ownsFDs;
public:
IoEvent(); // Creates a user event
IoEvent(int fd); // Create a file event
IoEvent(const IoEvent &other);
virtual ~IoEvent();
/**
* Set the event to signalled state.
*/
void set();
/**
* Reset the event from signalled state.
*/
void reset();
inline int fd() const {
return m_pipe[0];
}
};
IoEvent.cpp:
#include "IoEvent.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
using namespace std;
IoEvent::IoEvent() :
m_ownsFDs(true) {
if (pipe(m_pipe) < 0)
throw MyException("Failed to create pipe: %s (%d)", strerror(errno), errno);
if (fcntl(m_pipe[0], F_SETFL, O_NONBLOCK) < 0)
throw MyException("Failed to set pipe non-blocking mode: %s (%d)", strerror(errno), errno);
}
IoEvent::IoEvent(int fd) :
m_ownsFDs(false) {
m_pipe[0] = fd;
m_pipe[1] = -1;
}
IoEvent::IoEvent(const IoEvent &other) {
m_pipe[0] = other.m_pipe[0];
m_pipe[1] = other.m_pipe[1];
m_ownsFDs = false;
}
IoEvent::~IoEvent() {
if (m_pipe[0] >= 0) {
if (m_ownsFDs)
close(m_pipe[0]);
m_pipe[0] = -1;
}
if (m_pipe[1] >= 0) {
if (m_ownsFDs)
close(m_pipe[1]);
m_pipe[1] = -1;
}
}
void IoEvent::set() {
if (m_ownsFDs)
write(m_pipe[1], "x", 1);
}
void IoEvent::reset() {
if (m_ownsFDs) {
uint8_t buf;
while (read(m_pipe[0], &buf, 1) == 1)
;
}
}
You could ditch the m_ownsFDs
member; I'm not even sure I use that any more.
Cannot close listening socket to abort accept()/select() from a separate thread
close()
won't do what you want in the multithreaded case. Use one of the other mechanisms you describe instead.
In the single-threaded case, control returns to the select()
, which is restarted and notices EBADF on the now-dismissed file descriptor. (This is highly dangerous, of course, because fd #3 might be recycled by any other thread, or even a complex signal handler, at any time, though your toy program appears safe.) In the multi-threaded case, close()
just doesn't wake up your select()
ing thread.
The Python docs warn:
Note:
close()
releases the resource associated with a connection but does not necessarily close the connection immediately. If you want to close the connection in a timely fashion, callshutdown()
beforeclose()
.
In fact, this is a relatively thorny and platform-dependent problem. Excerpting a 2008 article in the venerable Dr Dobb's:
On some operating systems, [ shutdown() instead of close() ] is also the only working solution: On FreeBSD, a close() without shutdown() does not wake up the processes waiting in a read() or select()....
Another issue to consider is that closing by shutdown() or by close() may not be considered a read event in the OS....
However, shutdown() works only on the sockets with established connections, not on the ones listening for new connections nor on the other kinds of file descriptors....
(For what it's worth, on my system a shutdown()
does awaken the select()
ing thread.)
breaking out from socket select
The easiest way is probably to use pipe(2)
to create a pipe and add the read end to readfds
. When the other thread wants to interrupt the select()
just write a byte to it, then consume it afterward.
Related Topics
How to Install Maven on Redhat Linux
Is There a Limit on Number of Tcp/Ip Connections Between MAChines on Linux
Bash Scripting - How to Set the Group That New Files Will Be Created With
How to Read Websocket Response in Linux Shell
Is \D Not Supported by Grep's Basic Expressions
How to Find Ports Opened by Process Id in Linux
How to Append the Output to a File
Userspace VS Kernel Space Driver
Readelf VS. Objdump: Why Are Both Needed
Pass Output as an Argument for Cp in Bash
Remote Linux Server to Remote Linux Server Dir Copy. How
Unix: Differencebetween Source and Export
Recursively Cat All the Files into Single File
How to Gently Kill Firefox Process on Linux/Os X