2

I create in my class MainWindow a thread that launch a server, when I close this MainWindow, I need to stop that server, but I can't because the server running in a while(true) loop. So the only possibility I saw is to kill the thread containing the server.

But it's still not possible because I use #include <thread> and the C++11.

My solution was so to pass a boolean to my server, and to execute the loop, while this boolean is true. But I can't get out of my loop when my boolean become false, because my server wait to receive a frame that doesn't come before finish the loop.

Here's my code :

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //Some initialisation
...

    // Constructs the new thread and runs it. Does not block execution.
    m_t1 = std::thread(lancerServeur);

}

MainWindow::~MainWindow()
{
    delete ui;
    m_t1.join();
}


void MainWindow::lancerServeur(){
    serveur s;
    while(true){
        s.receiveDataUDP();//Wait for a frame
    }
}

So, is there a way to kill my thread in C++11, or do you see a way to stop my server ?

Thanks.

Evans Belloeil
  • 2,413
  • 7
  • 43
  • 76
  • 2
    You can't, not in a safe or portable way. Instead of having an infinite loop, you could have the loop check some variable (maybe a [condition variable](http://en.cppreference.com/w/cpp/thread/condition_variable)) and exit when set. – Some programmer dude Jun 26 '14 at 14:03
  • Not in a standard way, no. C++11 asserts that threads need to co-operate with each other; so the main thread will need to signal the child thread to exit. I remember reading about this as they added it to the spec, it relates to the stability of the program as a whole. If the thread is terminate form the outside, it could leave things in an indeterminate state. – Niall Jun 26 '14 at 14:03
  • @JoachimPileborg I can't because my server wait for a frame, and pause my thread. – Evans Belloeil Jun 26 '14 at 14:03
  • 1
    You need to modify `s.receiveDataUDP();` so that it doesn't block or uses an event. – 001 Jun 26 '14 at 14:05
  • @JohnnyMopp I need to wait a frame, how could it work if I don't wait. – Evans Belloeil Jun 26 '14 at 14:06
  • How about making the possibly blocking function [asynchronous](http://en.cppreference.com/w/cpp/thread/async)? – Some programmer dude Jun 26 '14 at 14:06
  • @JoachimPileborg First time I hear about that, how could I do that ? – Evans Belloeil Jun 26 '14 at 14:09
  • @JoachimPileborg Even if it is fired with `async` it will need to exit at some stage, either via the completion of a `promise/future` or on some application defined event. – Niall Jun 26 '14 at 14:13
  • @Niall Yes, but if the `std::async` call was made with an `async` [launch policy](http://en.cppreference.com/w/cpp/thread/launch) then destruction of the created thread and future will by asynchronous as well, and happen in the background. This means you can just return from the function that called `std::async`. – Some programmer dude Jun 26 '14 at 14:18
  • A way to solving my problem is to put my recvfrom to unblock mode... – Evans Belloeil Jun 26 '14 at 14:19
  • @JoachimPileborg, correct, but as it is written, the indefinite loop never exits, so it is never destroyed. – Niall Jun 26 '14 at 14:19
  • @EvansBelloeil Yes, if you can convert you udp calls to be asynch you would avoid the thread issue altogether. – 001 Jun 26 '14 at 14:32
  • In most networking libraries, closing the socket will have any outstanding blocking reads return. This in combination with a flag on the loop condition, as suggested by @JoachimPileborg should get you out of the loop. Of course you must make sure that you do not accidentally access the socket concurrently, unless your networking library is thread-safe. – ComicSansMS Jun 26 '14 at 15:19
  • @EvansBelloeil _'A way to solving my problem is to put my recvfrom to unblock mode...'_ what about a [`poll()`](http://linux.die.net/man/3/poll) loop or `select()` and create another [`eventfd()`](http://man7.org/linux/man-pages/man2/eventfd.2.html) to signal termination. – πάντα ῥεῖ Jun 26 '14 at 16:30
  • If your server is waiting in the thread, you should make it wait for more than one thing. In Qt, you'd be using a `QSocketNotifier` or a class derived from `QAbstractSocket`. In the latter case, you can simply invoke `quit()` on the `QThread`. There's absolutely no reason to use `while (true) { ... }` in your thread's `run` method. If you're using Qt, use it properly. – Kuba hasn't forgotten Monica Jun 26 '14 at 17:21
  • This question is related specifically to the Qt framework and is not a duplicate of a generic C++-11 question. – Kuba hasn't forgotten Monica Jun 26 '14 at 17:21
  • The biggest question that I have is this: why are you not using the `QUdpSocket` and the signals it provides? That's how you write asynchronous code: with signals and slots. Not with `waitForXxx`. – Kuba hasn't forgotten Monica Jun 26 '14 at 17:22
  • Why all that complex stuff? It's a UDP server - send it a datagram on the local stack that either, in itself, contains a 'stop' message, or just causes the readFrom() to return so that the thread can check a 'stop' boolean. – Martin James Jun 26 '14 at 18:53

3 Answers3

1

You need to have an event which the main thread will signal. Then your thread waits on both that event and receipt of the frame. When the wait returns, you check which condition caused the wait to end. If it was receipt of a frame, you process the frame and wait again. If it was the thread end event, you exit the thread.

I don't know the new standard threading libraries well enough yet to suggest how to do it using them. With the Windows native API you would use WaitForMultipleObjects().

Rob K
  • 8,757
  • 2
  • 32
  • 36
1

If it's a UDP server, and you want to unblock it so that it read some 'stop' boolean as true, set the boolean and send it a UDP message on the local stack, so unblocking it.

Martin James
  • 24,453
  • 3
  • 36
  • 60
0

You could create a pointer to the thread object and then delete the object in your destructor.

In other words:

    m_t1 = new std::thread(lancerServeur);

And then in your destructor:

    m_t1->detach();
    delete m_t1;

And of course change the memnber variable to a pointer:

    std::thread* m_t1;

or any other pointer of your choice.

EDIT: You must call 'm_t1->detach()' in your destructor as well to make sure the thread is not joinable when destroying. In the code sample you gave, this is not the case.

Ammar Husain
  • 1,789
  • 2
  • 12
  • 26