2015-02-06 3 views
1
struct root: public task 
{ 
root(){} 
tbb::task* execute(){ 
    tbb::task_list l; 
    tbb::task& c = *new(allocate_continuation()) tbb::empty_task; 
    int count=0; 
    // do what this task should do 
    while(condition){ 
    l.push_back(*new(c.allocate_child())root()); 
    ++count; 
    } 
    if(count){ 
    c.set_ref_count(count); 
    c.spawn(l); 
    } 
    return NULL; 
} 
}; 
main(){ 
    tbb::task_scheduler_init s(); 
    root& r = *new(tbb::task::allocate_root())root(); 
    tbb::task::spawn_root_and_wait(r); 
    return 0; 
} 

Привет, Я определить задачу TBB «корень», что делает некоторую работу и затем рекурсивно дальше, если condition в while цикл выполняется. Если count==0 после цикла while, что означает, что дальнейшая рекурсия не требуется, я не буду генерировать больше задач.ТВВ задача блокируется, если не рекурсии дальнейшего

Поскольку задача root не требует продолжения обновления, поэтому я использую tbb::empty_task как задачу продолжения.

Проблема заключается в том, что выполнение блокируется этим. Программа не может нормально вернуться. На данный момент мое решение:

if(!count){ 
    l.push_back(*new(c.allocate_child())tbb::empty_task); 
    c.spawn(l); 
    c.set_ref_count(1); 
} 

Однако, я полагаю, что цена - это производительность. Я хочу знать, почему исходный код не работает. Он работал в другом случае, когда задача продолжения не является пустой задачей. Я не совсем понимаю логику. Спасибо за любые комментарии.

ответ

0

Одна проблема в том, что когда count==0, задача c потеряна, так как у нее нет детей, и она не размножается. Правильный способ освободить задачу - позвонить tbb::task::destroy. Но поскольку вы выделили его в качестве продолжения, ответственность за то, чтобы сообщить об spawn_root_and_wait, что работа выполнена, переносится на задание c. И поскольку задача потеряна, сигнал также теряется, что приводит к тупику, который вы наблюдаете. Чтобы эффективно выполнять сигнализацию для случая count==0, просто верните указатель на эту задачу c в результате root::execute(), который похож на выполнение spawn(c), но позволяет избежать дополнительных накладных расходов для синхронизации.

Альтернатива состоит в том, чтобы сделать c.parent()->decrement_ref_count() и позвонить по телефону destroy(c) вручную.

+0

Спасибо. Он работает, когда я возвращаю указатель на задачу продолжения, а 'count == 0'. Однако, если я вместо этого делаю 'c.parent() -> decment_ref_count()' и 'task :: destroy (c)', он снова блокирует. Я думаю, что это связано с тем, что задача продолжения еще не порождена до ее уничтожения. – Alex

+0

@Alex, вы делаете декремент и уничтожаете только в 'count == 0' случае? задача может быть либо порождена, либо уничтожена, потому что порожденная задача уничтожается автоматически. Странно, что он все еще блокирует – Anton