0

Short explanation in bold.

I have a tbb::task that can be summed up like that:

class UpdateTask
: public tbb::task
{
public:
    tbb::task* execute()
    {
        // some work...

        if( can_continue() )
        {
            // make sure this is re-executed
            this->recycle_to_reexecute(); //looks like it is deprecated but it's more clear to me
                            return nullptr; // ? or this? or tbb::empty_task?

        }

        return nullptr;

    }

};

I want this task to be rescheduled as soon as its finished until a condition is filled. I'm allocating this task this way:

UpdateTask& updater = *new(tbb::task::allocate_root()) UpdateTask();

Not sure it's related to the problem though.

The problem: When I run the code, I get assertions (in Debug) from tbb (last revision, 4.1.5) and I can't find a way to make it work correctly.

I've re-read the documentation but I can't find a simple example of this and it is not clear to me what I'm doing wrong. I made some experiments:

  • With the code I just show, the assertion says that I should return a task: Assertion t_next failed on line 485 of file ...\itbb\src\tbb\custom_scheduler.h Detailed description: reexecution requires that method execute() return another task
  • Then if I return this, the assertions says that the task should be allocated: Assertion t_next->state()==task::allocated failed on line 452 of file ...\itbb\src\tbb\custom_scheduler.h Detailed description: if task::execute() returns task, it must be marked as allo cated
  • In doubt I tried to return a tbb::empty_task that I create on the fly (to check), allocated as new(tbb::task::allocate_child()) tbb::empty_task(). I got assertion with this message Assertion p.ref_count==0 failed on line 107 of file ...\itbb\src\tbb\custom_scheduler.h Detailed description: completion of task caused predecessor's reference count to underflow.

So, how to do it? I assume it is simple but can't find the way it is done. Is it related to task reference counting?


Update: here is a full code that is a good aproximation of what I have:

#include <iostream>
#include <atomic>

#include <tbb/tbb.h>

namespace test {    class UpdateTask        : public tbb::task  {   public:

        UpdateTask()        {           std::cout << "[UpdateTask]" << std::endl;       }

        ~UpdateTask()       {           std::cout << "\n[/UpdateTask]" << std::endl;        }

        tbb::task* execute()        {           std::cout << "Tick "<< m_count <<std::endl;

            ++m_count;

            // make sure this is re-executed            this->recycle_to_reexecute();           //return new(tbb::task::allocate_continuation()) tbb::empty_task();             return nullptr;         }

    private:

        std::atomic<int> m_count;

    };


    tbb::task_list m_task_list;


    void register_update_task()     {       UpdateTask& updater =
*new(tbb::task::allocate_root()) UpdateTask();      m_task_list.push_back( updater );   }

    void run_and_wait()     {       tbb::task::spawn_root_and_wait( m_task_list );  }

    void tbb_test()     {       register_update_task();         run_and_wait();

    }

}

int main()
{

    test::tbb_test();

    std::cout << "\nEND";
    std::cin.ignore();

    return 0;
}

So, here I got the first exception saying that I should return a task. In execute() function, if I replace the return by the one commented, then it appear to work, but there are two problems with this:

  • I have to create an empty_task task EVERY TIME a call to execute is done???
  • After the first call to execute(), the main thread is resumed. This is NOT what spawn_root_and_wait() is supposed to do. After all the task is not finished and is correctly rescheduled.

I must conclude it's not the right way to do this either.

Klaim
  • 67,274
  • 36
  • 133
  • 188
  • These assertions, do they display any error message? Could you add them please? – Some programmer dude Aug 07 '12 at 14:12
  • I copy pasted the assertions I got. – Klaim Aug 07 '12 at 14:18
  • It appears to me that the trick would be to have at least two tasks being the continuation of each other? I'm a bit lost... – Klaim Aug 07 '12 at 14:21
  • Are you deleting `updater` somewhere? Are you certain it is not deleted while the task is running? It may be helpful if you include that part of the code too. – Joost Sannen Aug 07 '12 at 15:18
  • Once spawned I don't own the task anymore, it should be managed by the task scheduler. I'll try to setup a simpler example. – Klaim Aug 07 '12 at 15:25
  • @JoostSannen Note that whatever the problem I have, just giving a simple example that work would be a good answer for me. – Klaim Aug 07 '12 at 15:26

1 Answers1

3

this->recycle_to_reexecute();

is deprecated.

Replace by:

this->increment_ref_count();
this->recycle_as_safe_continuation();

Enjoy

P.S.: end of course(in yours case) return NULL from execute.

Klaim
  • 67,274
  • 36
  • 133
  • 188
kain64b
  • 2,258
  • 2
  • 15
  • 27