简体   繁体   中英

epoll_wait() in a thread after close()

I have a main thread and a worker thread. The worker thread's code looks like something like this:

thread = ::std::thread([this]() {
    struct epoll_event events[50];

    for (;;)
    {
      if (int const n =
        epoll_wait(efd, events, 50, -1))
      {
      //...

I was hoping that a close(efd) in the main thread would cause the worker thread's epoll_wait() call to return, but it doesn't happen. What can I do to exit from the worker thread's infinite loop?

The simplest solution is probably as follows:

  1. Have the worker thread include the read end of a pipe in the epoll set.

  2. Code the worker thread to terminate if epoll_wait indicates the pipe is readable.

  3. To terminate the worker thread, write a byte to the write end of the pipe.

  4. Let the worker thread close the epoll socket, or close it after joining the worker.

Your best bet is to use an explicit signal (by which I mean, signal in the ordinary sense; not necessarily a POSIX signal) from the main thread to the epoll worker thread.

The technique of using a pipe for this purpose is tried and true, but there are much better options: check out eventfd . To use it, you would create an eventfd file descriptor and add it to the epoll set. Signal it from the main thread by writing an 8-byte value (a value of 1 is fine).

When the worker thread sees an event on the eventfd, it knows it has been signalled and should act accordingly.

The main advantage over using a pipe is that it requires only a single file descriptor, and you don't have to worry about the possibility of blocking when you write to the pipe.

I just had the same problem, and after doing some tests this worked for me:

I have one thread serving and waiting at epoll_wait, and one thread closing the connection. The closing thread was something like:

shutdown(server_fd, SHUT_RDWR);
close(server_fd);

And the server thread hangs indefinitely (except if the server thread is the main thread). So I isolated the problem to experiment a bit and try to understand it better, and found that removing the close line and only shutting down the server_fd without closing it is doing the work.

So, I answer my own question after a long time. Just as I noted in my comments, it's also possible to send a signal to the thread containing the epoll_wait() .

bool terminate_meh{};

extern "C"
{

static void sig_handler(int) noexcept
{
  terminate_meh = true;
}

}

{
  struct sigaction act{};

  act.sa_handler = sig_handler;
  sigemptyset(&act.sa_mask);

  sigaction(SIGUSR2, &act, {});
}

When you want to kill the waiting thread:

pthread_kill(thread.native_handle(), SIGUSR2);

any blocking function ( epoll_wait() ) will be interrupted and terminate_meh will be set.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM