Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need help for error: Assertion `this->load_steals() == 0' failed #33

Closed
Frandy opened this issue Mar 1, 2025 · 4 comments
Closed

Need help for error: Assertion `this->load_steals() == 0' failed #33

Frandy opened this issue Mar 1, 2025 · 4 comments

Comments

@Frandy
Copy link

Frandy commented Mar 1, 2025

I'm trying to use libfork for dag task, and got below code. It can get the correct output, but got assert error before exit. It is ok if with unit_pool.
Would you please give some help ?

build command
g++-14 test2.cpp -std=c++2b -I/usr/local/include/libfork-3.8.0/ -o test2

test2.cpp

#include <atomic>
#include <libfork.hpp>
#include <print>
#include <string>
#include <vector>

struct TaskNode {
    TaskNode(const std::string &name) : name(name) {}
    void execute() { std::println("executing task {}", name); }
    std::string name;
    std::vector<TaskNode *> dependencies;
    std::vector<TaskNode *> successors;
    std::atomic<int> remaining_dependencies{0};
};

inline constexpr auto process_node = [](auto process_node,
                                        TaskNode *node) -> lf::task<> {
    node->execute();

    for (TaskNode *successor : node->successors) {
        int previous = successor->remaining_dependencies.fetch_sub(
            1, std::memory_order_acq_rel);

        if (previous == 1) {
            co_await lf::fork(process_node)(successor);
        }
    }
};

inline constexpr auto run_dag =
    [](auto run_dag, std::vector<TaskNode *> &entries) -> lf::task<> {
    for (TaskNode *entry : entries) {
        co_await lf::fork(process_node)(entry);
    }
    // co_await lf::join();
};

int main() {
    TaskNode a("a"), b("b"), c("c"), d("d"), e("e");

    a.successors = {&b};

    b.dependencies = {&a};
    b.successors = {&c};

    c.dependencies = {&b};

    d.successors = {&e};
    e.dependencies = {&d};

    for (TaskNode *node : {&a, &b, &c, &d, &e}) {
        node->remaining_dependencies.store(node->dependencies.size(),
                                           std::memory_order_relaxed);
    }

    std::vector<TaskNode *> entries;
    for (TaskNode *node : {&a, &b, &c, &d, &e}) {
        if (node->remaining_dependencies.load(std::memory_order_relaxed) == 0) {
            entries.push_back(node);
        }
    }

    lf::lazy_pool pool(2);
    // lf::unit_pool pool;

    lf::sync_wait(pool, run_dag, entries);

    return 0;
}

the output as below
executing task d
executing task e
executing task a
executing task b
executing task c
test2: /usr/local/include/libfork-3.8.0/libfork/core/impl/promise.hpp:308: auto lf::impl::promise<R, I, Tag>::final_suspend() const [with R = void; I = std::shared_ptr<lf::impl::future_shared_state >; lf::core::tag Tag = lf::core::tag::root]: Assertion `this->load_steals() == 0' failed.
Aborted (core dumped)

@ConorWilliams
Copy link
Owner

ConorWilliams commented Mar 5, 2025

It looks like you have no joins, every fork requires a join.

Also libfork provides a for_each primitive that will get you better performance than this

@Frandy
Copy link
Author

Frandy commented Mar 7, 2025

It looks like you have no joins, every fork requires a join.

Also libfork provides a for_each primitive that will get you better performance than this

Thanks for your reply. now I added two lf::join , but got below compile error.
new add code as below

Image

error

test2.cpp: In lambda function:
test2.cpp:28:22: error: no match for call to ‘(const lf::impl::join_type) ()’
   28 |     co_await lf::join();
      |              ~~~~~~~~^~
test2.cpp: In lambda function:
test2.cpp:34:26: warning: ‘static auto lf::impl::bind_task<Tag, Mod>::operator()(F&&) [with F = const<lambda(auto:86, TaskNode*)>&; lf::core::tag Tag = lf::core::tag::fork; Mod = lf::core::modifier::none]’ is deprecated: Use operator[] instead of operator() [-Wdeprecated-declarations]
   34 |         co_await lf::fork(process_node)(entry);
      |                  ~~~~~~~~^~~~~~~~~~~~~~
In file included from /usr/local/include/libfork-3.8.0/libfork/core.hpp:13:
/usr/local/include/libfork-3.8.0/libfork/core/control_flow.hpp:82:55: note: declared here
   82 |   LF_DEPRECATE_CALL [[nodiscard]] LF_STATIC_CALL auto operator()(F &&fun) LF_STATIC_CONST {
      |                                                       ^~~~~~~~
test2.cpp:34:26: warning: ‘static auto lf::impl::bind_task<Tag, Mod>::operator()(F&&) [with F = const<lambda(auto:86, TaskNode*)>&; lf::core::tag Tag = lf::core::tag::fork; Mod = lf::core::modifier::none]’ is deprecated: Use operator[] instead of operator() [-Wdeprecated-declarations]
   34 |         co_await lf::fork(process_node)(entry);
      |                  ~~~~~~~~^~~~~~~~~~~~~~
/usr/local/include/libfork-3.8.0/libfork/core/control_flow.hpp:82:55: note: declared here
   82 |   LF_DEPRECATE_CALL [[nodiscard]] LF_STATIC_CALL auto operator()(F &&fun) LF_STATIC_CONST {
      |                                                       ^~~~~~~~
test2.cpp:36:22: error: no match for call to ‘(const lf::impl::join_type) ()’
   36 |     co_await lf::join();
      |              ~~~~~~~~^~

@ConorWilliams
Copy link
Owner

Join is an object that can be directly awaited you don't need the parentheses

@Frandy
Copy link
Author

Frandy commented Mar 7, 2025

Join is an object that can be directly awaited you don't need the parentheses

Yeah!
Thank you very much.

@Frandy Frandy closed this as completed Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants