TBB 任务分配断言

发布于 2024-12-13 11:34:50 字数 1660 浏览 1 评论 0原文

我正在尝试通过 TBB 任务和延续来遍历树。代码如下。当我运行代码时,它不断中止(经常,但并非总是),并出现以下错误:

文件 ../../src/tbb/custom_scheduler.h 第 334 行断言 t_next->state()==task::allocated 失败 详细说明:如果task::execute()返回任务,则必须将其标记为已分配

什么可能导致这个问题?

template<class NodeVisitor>
void
traverse_tree(NodeVisitor& nv)
{
    TreeTraversal<NodeVisitor>&  tt = *(new(task::allocate_root()) TreeTraversal<NodeVisitor>(nv));
    task::spawn_root_and_wait(tt);
}

template<class NodeVisitor>
class TreeTraversal: public task
{
    public:
        struct Continuation;

    public:
                    TreeTraversal(NodeVisitor nv_):
                        nv(nv_)                                     {}

        task*       execute()
        {
            nv.pre();

            Continuation* c = new(allocate_continuation()) Continuation(nv);
            c->set_ref_count(nv.size());
            for (size_t i = 0; i < nv.size(); ++i)
            {
                TreeTraversal& tt =  *(new(c->allocate_child()) TreeTraversal(nv.child(i)));
                spawn(tt);
            }

            if (!nv.size())
                return c;

            return NULL;
        }

    private:
        NodeVisitor     nv;
};

template<class NodeVisitor>
class TreeTraversal<NodeVisitor>::Continuation: public task
{
    public:
                        Continuation(NodeVisitor& nv_):
                            nv(nv_)                             {}
        task*           execute()                               { nv.post(); return NULL; }

    private:
        NodeVisitor     nv;
};

I'm trying to traverse a tree via TBB tasks and continuations. The code is below. When I run the code it keeps aborting (frequently, although not always) with the following error:

Assertion t_next->state()==task::allocated failed on line 334 of file ../../src/tbb/custom_scheduler.h
Detailed description: if task::execute() returns task, it must be marked as allocated

What can be causing this problem?

template<class NodeVisitor>
void
traverse_tree(NodeVisitor& nv)
{
    TreeTraversal<NodeVisitor>&  tt = *(new(task::allocate_root()) TreeTraversal<NodeVisitor>(nv));
    task::spawn_root_and_wait(tt);
}

template<class NodeVisitor>
class TreeTraversal: public task
{
    public:
        struct Continuation;

    public:
                    TreeTraversal(NodeVisitor nv_):
                        nv(nv_)                                     {}

        task*       execute()
        {
            nv.pre();

            Continuation* c = new(allocate_continuation()) Continuation(nv);
            c->set_ref_count(nv.size());
            for (size_t i = 0; i < nv.size(); ++i)
            {
                TreeTraversal& tt =  *(new(c->allocate_child()) TreeTraversal(nv.child(i)));
                spawn(tt);
            }

            if (!nv.size())
                return c;

            return NULL;
        }

    private:
        NodeVisitor     nv;
};

template<class NodeVisitor>
class TreeTraversal<NodeVisitor>::Continuation: public task
{
    public:
                        Continuation(NodeVisitor& nv_):
                            nv(nv_)                             {}
        task*           execute()                               { nv.post(); return NULL; }

    private:
        NodeVisitor     nv;
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

楠木可依 2024-12-20 11:34:50

我以前从未见过任务被分配为延续,然后从 execute() 返回。这可能是断言失败的原因(更新:实验表明并非如此,请参阅下面的详细信息)。

同时,您可以将 TreeTraversal::execute() 的代码更改为大致如下:

nv.pre();
if (!nv.size())
    nv.post();
else {
    // Do all the task manipulations
}
return NULL;

更新:下面所示的简化测试在我的双核笔记本电脑上运行良好。这让我假设您的实际代码中可能存在内存损坏,在这种情况下,上面建议的重新洗牌可能只是隐藏问题而不是解决它。

#include "tbb/task.h"
using namespace tbb;

class T: public task {
public:
    class Continuation: public task {
    public:
        Continuation() {}
        task* execute() { return NULL; }
    };

private:
    size_t nv;

public:
    T(size_t n): nv(n) {}

    task* execute() {
        Continuation* c = new(allocate_continuation()) Continuation();
        c->set_ref_count(nv);
        for (size_t i = 0; i < nv; ++i) {
            T& tt =  *(new(c->allocate_child()) T(nv-i-1));
            spawn(tt);
        }
        return (nv==0)? c : NULL;
    }
};

int main() {
    T& t = *new( task::allocate_root() ) T(24);
    task::spawn_root_and_wait(t);
    return 0;
}

I have never seen before that a task is allocated as a continuation and then returned from execute(). That might be the reason of the assertion failure (update: an experiment showed it is not, see details below).

Meanwhile, you can change the code of TreeTraversal::execute() to be roughly this:

nv.pre();
if (!nv.size())
    nv.post();
else {
    // Do all the task manipulations
}
return NULL;

Update: a simplified test shown below worked well on my dual-core laptop. That makes me suppose possible memory corruption in your actual code, in which case the re-shuffling suggested above might just hide the issue but not fix it.

#include "tbb/task.h"
using namespace tbb;

class T: public task {
public:
    class Continuation: public task {
    public:
        Continuation() {}
        task* execute() { return NULL; }
    };

private:
    size_t nv;

public:
    T(size_t n): nv(n) {}

    task* execute() {
        Continuation* c = new(allocate_continuation()) Continuation();
        c->set_ref_count(nv);
        for (size_t i = 0; i < nv; ++i) {
            T& tt =  *(new(c->allocate_child()) T(nv-i-1));
            spawn(tt);
        }
        return (nv==0)? c : NULL;
    }
};

int main() {
    T& t = *new( task::allocate_root() ) T(24);
    task::spawn_root_and_wait(t);
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文