2

I have std::thread which listens for netlink events from the Linux kernel, It has an infinite while loop and a blocking function which blocks until the next event. I want to stop the thread forcefully in the program workflow when I don't need that anymore.

Here is my current solution:

#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <iostream>
#include <thread>
#include <signal.h>

void thread_func() {
    while(true) {
        std::cout << "Processing events.." << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(10)); // simulating a blocking function that blocks until next events
        std::cout << "Events received.." << std::endl;
    }
}

int main() {
    std::thread eventListener(thread_func);
    std::this_thread::sleep_for(std::chrono::seconds(3)); // doing some work in main thread
    pthread_cancel(eventListener.native_handle()); // I don't want the eventListener anymore
    eventListener.join();
    std::cout << "eventListener killed" << std::endl;
    return 0;
}

My program only compiles to the Linux platform.

It's the actual blocking function from libnl nl_recvmsgs_default(nl_sock* sock)

Questions:

  1. Is it the correct way of doing it in C++? or I'm missing some minor details here?
  2. Is there any other better way of achieving this?
  3. if I change the above code to kill the thread by pthread_kill instead of pthread_cancel then I don't see the print "eventListener killed" in output, I don't know why?

Update: Setting a flag is not working for me, as I don't even know how long the function will get blocked, if I don't receive any new events from the kernel then the function never gets resumed and in that case, I just need to wait after setting the flag to true (until the next iteration of while loop on new netlink event from the kernel).

Vencat
  • 1,272
  • 11
  • 36
  • 1
    It's almost definitely a wrong approach. Tell us what function is blocking, and we can think how to stop it early. – HolyBlackCat Feb 12 '23 at 13:00
  • 1
    There is no safe way to kill a thread that is stuck in a function call. Imagine that the thread is holding a mutex or other lock say on the heap (or any other stateful condition). If you killed the thread the lock would remain locked leaving the program in an unknown state. Unlike killing a program where the kernel cleans up any remaining mess, killing a thread does not clean up any resources in use by the thread. – Richard Critten Feb 12 '23 at 13:20
  • @RichardCritten Just wonder then why there are functions like `pthread_kill` exist in POSIX – Vencat Feb 12 '23 at 13:37
  • If you know exactly what the function does ie you have written it or can inspect the source then I guess it could be safe to kill the thread. If it's an external (block-box) function that does anything remotely complex then the entire state of the program is at risk if you kill it. – Richard Critten Feb 12 '23 at 13:39
  • See also [Is there any way to kill a Thread? (952 votes)](https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread) – Richard Critten Feb 12 '23 at 13:43
  • Use [non-blocking](https://www.infradead.org/~tgr/libnl/doc/api/group__socket.html#gaa5eeee12e085b1731ba92edbd150ef2a) reads on the socket and end the thread naturally. – Galik Feb 12 '23 at 18:27
  • @Galik if I set the socket non-blocking, then I need to poll periodically for messages, isn't it? – Vencat Feb 12 '23 at 19:46
  • @Vencat, `pthread_kill()` can send *any* signal to a thread. The result depends on a lot of factors, but it does not necessarily involve the target thread terminating abruptly. – John Bollinger Feb 14 '23 at 14:35

1 Answers1

2

Redesign so your thread doesn't use blocking operations.

Netlink is implemented as socket I/O, so you can nl_socket_set_nonblocking and then use "interruptible" I/O multiplexing like poll or select to wait for activity.

Add a humble pipe, so that your looping thread is input-multiplexing on both the netlink socket and the read end of the pipe. When it is time to end the loop, have some other thread close the write end — the read end will immediately present as readable (for EOF) and your looping thread will know its work is done.

You can prototype this approach with a simple multithreaded program that blocks on stdin, for example, rather than a netlink socket.

pilcrow
  • 56,591
  • 13
  • 94
  • 135