2

I have a vector of Timer Objects. Each Timer Object launches an std::thread that simulates a growing period. I am using a Command pattern.

What is happening is each Timer is getting executed one after another but what I really want is for one to be executed....then once finished, the next one...once finished the next...while not interfering with the main execution of the program

class Timer 
{
    public:

        bool _bTimerStarted;
        bool _bTimerCompleted;

        int _timerDuration;

        virtual ~Timer() { }
        virtual void execute()=0;
        virtual void runTimer()=0;

        inline void setDuration(int _s) { _timerDuration = _s; };
        inline int getDuration() { return _timerDuration; };

        inline bool isTimerComplete() { return _bTimerCompleted; };
};

class GrowingTimer : public Timer
{
    public:
        void execute()
        {
            //std::cout << "Timer execute..." << std::endl;

            _bTimerStarted = false;
            _bTimerCompleted = false;

            //std::thread t1(&GrowingTimer::runTimer, this); //Launch a thread
            //t1.detach();

            runTimer();
        }

        void runTimer()
        {
            //std::cout << "Timer runTimer..." << std::endl;

            _bTimerStarted = true;

            auto start = std::chrono::high_resolution_clock::now();
            std::this_thread::sleep_until(start + std::chrono::seconds(20));

            _bTimerCompleted = true;

            std::cout << "Growing Timer Finished..." << std::endl; 
        }
};

class Timers
{
    std::vector<Timer*> _timers;

    struct ExecuteTimer
    {
        void operator()(Timer* _timer) { _timer->execute(); }
    };

    public:
        void add_timer(Timer& _timer) { _timers.push_back(&_timer); }

        void execute()
        {
            //std::for_each(_timers.begin(), _timers.end(), ExecuteTimer());

            for (int i=0; i < _timers.size(); i++)
            {
                 Timer* _t = _timers.at(i);
                _t->execute();

                //while ( ! _t->isTimerComplete())
                //{

                //}
            }
        }
};

Executing the above like:

Timers _timer;
GrowingTimer _g, g1;

_g.setDuration(BROCCOLI::growTimeSeconds);
_g1.setDuration(BROCCOLI::growTimeSeconds);

_timer.add_timer(_g);
_timer.add_timer(_g1);

start_timers();

}

void start_timers() 
{
    _timer.execute();
}

In Timers::execute I am trying a few different ways to execute the first and not execute the next until I somehow signal it is done.

UPDATE:

I am now doing this to execute everything:

Timers _timer;
GrowingTimer _g, g1;

_g.setDuration(BROCCOLI::growTimeSeconds);
_g1.setDuration(BROCCOLI::growTimeSeconds);

_timer.add_timer(_g);
_timer.add_timer(_g1);

//start_timers();

std::thread t1(&Broccoli::start_timers, this); //Launch a thread
t1.detach();

}

void start_timers() 
{
    _timer.execute();
}

The first time completes (I see the "completed" cout), but crashes at _t->execute(); inside the for loop with an EXEC_BAD_ACCESS. I added a cout to check the size of the vector and it is 2 so both timers are inside. I do see this in the console:

this    Timers *    0xbfffd998
_timers std::__1::vector<Timer *, std::__1::allocator<Timer *> >

if I change the detach() to join() everything completes without the crash, but it blocks execution of my app until those timers finish.

Jasmine
  • 15,375
  • 10
  • 30
  • 48
  • 2
    You have a data race: simultaneous accesses to `Timer::_bTimerCompleted` in separate threads, one of which is a modification. Programs with data races have undefined behavior. You need to somehow synchronize access to `_bTimerCompleted`, such as by making it a `std::atomic`. – Casey Aug 07 '13 at 04:51

3 Answers3

3

Why are you using threads here? Timers::execute() calls execute on a timer, then waits for it to finish, then calls execute on the next, and so forth. Why don't you just call the timer function directly in Timers::execute() rather than spawning a thread and then waiting for it?

Threads allow you to write code that executes concurrently. What you want is serial execution, so threads are the wrong tool.

Update: In the updated code you run start_timers on a background thread, which is good. However, by detaching that thread you leave the thread running past the end of the scope. This means that the timer objects _g and _g1 and even the Timers object _timers are potentially destroyed before the thread has completed. Given the time-consuming nature of the timers thread, and the fact that you used detach rather than join in order to avoid your code blocking, this is certainly the cause of your problem.

If you run code on a thread then you need to ensure that all objects accessed by that thread have a long-enough lifetime that they are still valid when the thread accesses them. For detached threads this is especially hard to achieve, so detached threads are not recommended.

One option is to create an object containing _timers, _g and _g1 along side the thread t1, and have its destructor join with the thread. All you need to do then is to ensure that the object lives until the point that it is safe to wait for the timers to complete.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
  • I am using threads because otherwise while the timers are executing it halts execution of the program and I can't do anything until they are finished and I need the app to continue running – Jasmine Aug 07 '13 at 15:52
  • As you've written it, the thread that runs `Timers::execute()` is blocked anyway. You could run *that* on a background thread. – Anthony Williams Aug 07 '13 at 15:55
  • I'm still not exactly following. are you talking about when I run `_timers.execute() from the main code? – Jasmine Aug 07 '13 at 16:20
  • THanks for the update. All I really need to do is *delay* running a function for x seconds and not halt the execution of the main thread (i.e continue the app going, users doing stuff). The delay is to show that things take time to grow......any ideas? I can see now where threads might not be the best choice. – Jasmine Aug 09 '13 at 04:30
  • You could just check the clock. Store `std::chrono::steady_clock::now()+std::chrono::seconds(whatever)` to indicate when your function should be run. In the main loop, call the function if `std::chrono::steady_clock::now()` is greater than the stored time. – Anthony Williams Aug 09 '13 at 07:27
  • But say I want something delayed 8 minutes, I cant just check once in the main loop. I need to check if more often, right? How does one do that without tying up the main loop again? a While {} would tie it up – Jasmine Aug 09 '13 at 14:59
  • Wow, I had no idea you were the author of a concurrency book, until this morning when I was reading a Solarian Programmer article. – Jasmine Aug 09 '13 at 18:13
  • Main loop: `while(not_done_with_main_loop()){if(std::chrono::steady_clock::now()>target_time) {run_timer_callback();} do_rest_of_main_loop();}` – Anthony Williams Aug 10 '13 at 18:21
  • Of course, if the "main loop" is not a *loop* then you'll have to do this differently --- put the check at strategic points in the code. – Anthony Williams Aug 10 '13 at 18:23
1

You could include a unique_ptr to the thread in GrowingTimer instead of creating it as a local object in execute and calling detach. You can still create the thread in execute, but you would do it with a unique_ptr::reset call.

Then use join instead of isTimerComplete (add a join function to the Timer base class). The isTimerComplete polling mechanism will be extremely inefficient because it will basically use up that thread's entire time slice continually polling, whereas join will block until the other thread is complete.

An example of join:

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

using namespace std;

void threadMain()
{
    this_thread::sleep_for(chrono::seconds(5));

    cout << "Done sleeping\n";
}

int main()
{
    thread t(threadMain);

    for (int i = 0; i < 10; ++i)
    {
        cout << i << "\n";
    }

    t.join();

    cout << "Press Enter to exit\n";

    cin.get();
    return 0;
}

Note how the main thread keeps running while the other thread does its thing. Note that Anthony's answer is right in that it doesn't really seem like you need more than one background thread that just executes tasks sequentially rather than starting a thread and waiting for it to finish before starting a new one.

Joel
  • 1,135
  • 6
  • 9
  • can you show me an example of this? my understanding is that join() will block the rest of the app from executing. – Jasmine Aug 07 '13 at 15:54
  • `join` will block the calling thread, not the entire application. I added an example of it just to show it, but my answer is a better way of detecting when a thread has exited than polling on a `bool`, while Anthony's is probably what you should really do in this case. – Joel Aug 08 '13 at 01:55
  • so essentially I want to create a thread that does a detach and in that thread spawn another thread to run the chrono() and use join() so that the main app keeps going and these chrono() calls are run seperate – Jasmine Aug 08 '13 at 15:32
1

If you don't want to interfere with the execution of the program, you could do something like @Joel said but also adding a thread in the Timers class which would execute the threads in the vector.