Terminate thread c++11 blocked on read

前端 未结 2 1950
梦如初夏
梦如初夏 2021-02-10 20:59

I\'ve got the following code:

class Foo {
private:
    std::thread thread;
    void run();
    std::atomic_flag running;
    std::thread::native_handle_type nati         


        
相关标签:
2条回答
  • 2021-02-10 21:21

    As others have said, killing a running thread is a Bad Idea™.

    However, in this case, you somehow know the thread is blocking on a read, and want it to stop.

    A simple way of doing this is to use the "self pipe trick". Open a pipe, and have the thread block on a select() or poll() call, checking the read end of the pipe and the file descriptor being read. When you want the thread to stop, write a single byte to the write descriptor. The thread wakes up, sees the byte on the pipe and can then terminate.

    This approaches avoids the undefined behaviour of killing a thread outright, allows you to use a blocking system call to avoid polling and is responsive to a termination request.

    0 讨论(0)
  • 2021-02-10 21:22

    As you can see here the thread is blocked on a read system call. So even if I clear the flag the thread will be still blocked and join call will block forever.

    The solution to this is to std::raise a signal such as SIGINT Edit: You need to raise the signal using pthread_kill so that the signal will be handled by the correct thread. As you can read from the manual, read is interrupted by signals. You must handle the std::signal or else the entire process will terminate prematurely.

    On systems that use BSD signal handling instead of POSIX, system calls are by default restarted rather than failed upon interrupt. My suggested approach relies on the POSIX behaviour, where the call sets EINTR and returns. The POSIX behaviour can set explicitly using siginterrupt. Another option is to register the signal handler using sigaction, which does not restart, unless specified by a flag.

    After read has been interrupted, you must check whether the thread should stop before retrying the read.

    using c++11 (maybe even without it) don't call any blocking system call in the thread

    Calling blocking system calls is just fine. What you shouldn't do is call uninterruptible system calls that may block indefinitely long time, if you wish to terminate the thread without terminating the process (within finite time). Off the top of my head, I don't know if any system call matches such description.

    A minimal example (complete except for indefinitely blocking read. You can use sleep(100000) to simulate it):

    #include <thread>
    #include <iostream>
    #include <csignal>
    #include <cerrno>
    #include <unistd.h>
    
    constexpr int quit_signal = SIGINT;
    thread_local volatile std::sig_atomic_t quit = false;
    
    int main()
    {
        // enforce POSIX semantics
        siginterrupt(quit_signal, true);
    
        // register signal handler
        std::signal(quit_signal, [](int) {
            quit = true;
        });
    
        auto t = std::thread([]() {
            char buf[10];
            while(!quit) {
                std::cout << "initiated read\n";
                int count = read(some_fd_that_never_finishes, buf, sizeof buf);
                if (count == -1) {
                    if (errno == EINTR) {
                        std::cout << "read was interrupted due to a signal.\n";
                        continue;
                    }
                }
            }
            std::cout << "quit is true. Exiting\n";;
        });
    
        // wait for a while and let the child thread initiate read
        sleep(1);
    
        // send signal to thread
        pthread_kill(t.native_handle(), quit_signal);
    
        t.join();
    }
    

    Forcibly killing a thread is usually a very bad idea, especially in C++, which is probably why std::thread API doesn't provide interface for it.

    If you really want to kill a thread of execution - which isn't necessary in this case, since you can safely interrupt the system call instead - then you should use a child process instead of child thread. Killing a child process won't break the heap of the parent process. That said, C++ standard library does not provide an inter-process API.

    0 讨论(0)
提交回复
热议问题