2

I am trying to run run() function every 5 seconds without stopping while() loop (parallelly). How can I do that ? Thanks in advance

    #include <iostream>
    #include <thread>
    #include <chrono>

    using namespace std;

    void run() 
    {
        this_thread::sleep_for(chrono::milliseconds(5000));

        cout << "good morning" << endl;
    }


    int main()
    {
        thread t1(run);
        t1.detach();

        while(1)
        {
            cout << "hello" << endl;

            this_thread::sleep_for(chrono::milliseconds(500));
        }

        return 0;
    }
user6200763
  • 59
  • 1
  • 7
  • 6
    Can you just use a `while` loop inside of `run()`? – jtbandes Feb 11 '20 at 06:58
  • 3
    Please take a couple of steps back, eat some good dinner, and go to sleep. In the morning, after a healthy breakfast, the solution (already mentioned above) should hopefully be pretty obvious. – Some programmer dude Feb 11 '20 at 07:02
  • this is a small simulation of a bigger code so assume there are lines of codes in while loop and they should not be stopped / waited. – user6200763 Feb 11 '20 at 07:05
  • :) sorry I m new on threads @Someprogrammerdude – user6200763 Feb 11 '20 at 07:07
  • 4
    Also there is no reason to use `detach` here (there rarely is a good reason for doing so) – Alan Birtles Feb 11 '20 at 07:07
  • Does this answer your question? [c++ Implementing Timed Callback function](https://stackoverflow.com/questions/12904098/c-implementing-timed-callback-function) – amin saffar Feb 11 '20 at 07:08
  • currently all answers assume that the runtime of ``run()`` is negligible. If ``run()`` takes a small but not negligible time, you might want to look into ``sleep_until``. If ``run()`` takes more than 5 seconds, then you can not longer combine ``run()`` with the sleep, but would need to start a new thread (or task if you have a threadpool) every 5 seconds. –  Feb 11 '20 at 08:42
  • @generic_opto_guy if run() takes more than 5 seconds and you spawn new thread for run() every 5 seconds eventually you will exceed system limits. – idris Feb 11 '20 at 12:06
  • @idris would this even happen when I join all finished threads befor I spawn a new thread? –  Feb 11 '20 at 12:12
  • @generic_opto_guy it will not happen. But if you wait for spawn thread that mean you call run() function more than per 5 sec. – idris Feb 11 '20 at 12:17

2 Answers2

4

In your main function, it is important to understand what each thread is doing.

  1. The main thread creates a std::thread called t1
  2. The main thread continues and detaches the thread
  3. The main thread executes your while loop in which it:
    • prints hello
    • sleeps for 0.5 seconds
  4. The main thread returns 0, your program is finished.

Any time from point 1, thread t1 sleeps for 5 seconds and then prints good morning. This happens only once! Also, as pointed out by @Fareanor, std::cout is not thread-safe, so accessing it with the main thread and thread t1 may result in a data race.

When the main thread reaches point 4 (it actually never does because your while loop is infinite), your thread t1 might have finished it's task or not. Imagine the potential problems that could occur. In most of the cases, you'll want to use std::thread::join().

To solve your problem, there are several alternatives. In the following, we will assume that the execution of the function run without the std::this_thread::sleep_for is insignificant compared to 5 seconds, as per the comment of @Landstalker. The execution time of run will then be 5 seconds plus some insignificant time.

As suggested in the comments, instead of executing the function run every 5 seconds, you could simply execute the body of run every 5 seconds by placing a while loop inside of that function:

void run() 
{
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(5000));
        std::cout << "good morning" << std::endl;
    }
}

int main()
{
    std::thread t(run);
    t.join();
    return 0;
}

If, for some reason, you really need to execute the run function every 5 seconds as stated in your question, you could launch a wrapper function or lambda which contains the while loop:

void run() 
{
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    std::cout << "good morning" << std::endl;
}

int main()
{
    auto exec_run = [](){ while (true) run(); };
    std::thread t(exec_run);
    t.join();
    return 0;
}

As a side note, it's better to avoid using namespace std.

mfnx
  • 2,894
  • 1
  • 12
  • 28
  • 2
    Good answer, this should be the accepted one. But you could improve something. In the `main()` OP has written an infinite `while` loop. So your step 4 never happens (_"When the main thread reaches point 4"_). – Fareanor Feb 11 '20 at 08:17
  • 1
    What will happen if the processing time associated with the thread greatly exceeds 5 seconds? suppose 5 minutes! The function will not be recalled at minute 1, nor at minute 2 ... If this is the desired bihaviour "ok". Otherwise, if you want that the function must be called every 5 seconds regardless of its processing time, this model is not suitable. – Landstalker Feb 11 '20 at 13:33
  • 1
    @Landstalker you are right. However, I think this is not the issue of the asker. The question would have been asked differently in my opinion. – mfnx Feb 11 '20 at 13:45
  • @mfnx Ok, it was just to make sure we met her need. – Landstalker Feb 11 '20 at 13:47
  • This is actually what @generic_opto_guy has already commented on the question. But since the OP did not say anything about what should the `run()` function do, except a single `std::cout`, these considerations are not a concern here (but I agree it deserved to me mentioned). – Fareanor Feb 11 '20 at 13:54
  • @Landstalker I added a few lines to make this clear. – mfnx Feb 11 '20 at 14:04
  • @mfnx I see. I find it more precise now with your modifications. now there is more ambiguity – Landstalker Feb 11 '20 at 14:09
1

Just call your run function in seperate thread function like below. Is this ok for you?

void ThreadFunction()
{
    while(true) {
        run();
        this_thread::sleep_for(chrono::milliseconds(5000));
    }
}

void run() 
{
    cout << "good morning" << endl;
}


int main()
{
    thread t1(ThreadFunction);
    t1.detach();

    while(1)
    {
        cout << "hello" << endl;

        this_thread::sleep_for(chrono::milliseconds(500));
    }

    return 0;
}
idris
  • 488
  • 3
  • 6
  • 2
    And does this really call `run` every _5_ seconds? ;) – Lukas-T Feb 11 '20 at 07:35
  • eyvallah hocam :) – user6200763 Feb 11 '20 at 07:37
  • @churill yes it will. What is your doubt? – idris Feb 11 '20 at 07:39
  • @idris `run()` will sleep 5 seconds and at the end of the `while` it will sleep 5 seconds again. Makes 10 if I'm not mistaken. – Lukas-T Feb 11 '20 at 07:57
  • @churill you right. What is happenning in run function can varry. I think it is a just stub function. – idris Feb 11 '20 at 08:01
  • @idris Your function does not wait 5 seconds but 10. Morevover, you don't need to nest a function inside another one. Only one run function is enough, there was only a missing `while` loop as the first question's comments mentioned. – Fareanor Feb 11 '20 at 08:10
  • 4
    Another thing, `std::cout` is not thread-safe if I'm not mistaken. So having two threads accessing `std::cout` concurrently without synchronization mechanism (mutex, ...) is a data race. – Fareanor Feb 11 '20 at 08:19
  • @Fareanor you are right but the question is not about what is happening in run function. I just copy the code. – idris Feb 11 '20 at 08:21
  • 2
    @idris Yes but StackOverflow is not meant to provide wrong answers. You should at least give advises, let OP know what is wrong in his code and propose a better way to achieve his/her goal. Completeness is a key to a good answer. Copying something wrong is... wrong. – Fareanor Feb 11 '20 at 08:23
  • @churill; @Fareanor (and therefore @Idris) your analysis is not correct. Wait times do not add up because the two 5 second waits **this_thread :: sleep_for (chrono :: milliseconds (500));** run on two different threads : the first sleep runs on the main thread (relating to the main function), the second on the t1 thread. knowing that the two threads **main function thread** and **t1** live their lives separately ... until the end of the "main thread" program. – Landstalker Feb 11 '20 at 11:47
  • We cannot add up (in the sense +) the execution time (5s + 5s = 10s) of two entities (threads, process) which execute in parallel especially if they do not have direct constraints synchronization between them. – Landstalker Feb 11 '20 at 12:03
  • @Landstalker You are wrong, the answer has been edited after our comments. If you have taken a look at the edits, you would have seen that in the original version of the answer, there was 2 `sleep_for(5000)` in the thread (one in run and another one in the `ThreadFunction`), not only one, hence the 10s. – Fareanor Feb 11 '20 at 13:42
  • @Fareanor Ok, i understend. That why I prefered indicated precisely which sleep is concerned: the sleep of the **main_thread** and the sleep of **ThreadFunction** – Landstalker Feb 11 '20 at 13:46
  • @Landstalker We are aware of it but we never talked about the main thread sleep. Before the edit, there was 2 sleeps in the same thread, that's all. Next time, be much careful and look at the edit/answer's improvements before claiming that other people's "analyses are not correct" ;) – Fareanor Feb 11 '20 at 13:50
  • @Fareanor Thanks ;) – Landstalker Feb 11 '20 at 13:53
  • @Landstalker No problem, without knowing the whole story, I can easily understand that the comments may appear quite surprising :) – Fareanor Feb 11 '20 at 14:02