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

Unexpected result with read/write zip_view and parallel_for_each #1643

Open
rubenvb opened this issue Feb 20, 2025 · 1 comment
Open

Unexpected result with read/write zip_view and parallel_for_each #1643

rubenvb opened this issue Feb 20, 2025 · 1 comment
Assignees
Labels

Comments

@rubenvb
Copy link

rubenvb commented Feb 20, 2025

Summary

parallel_for_each gives a different result than std::ranges::for_each when passing a read/write std::ranges::zip_view.

Version

2021.4, 2021.10

Environment

  • Hardware: x86_64 and aarch64
  • OS name and version: LInux, macOS 15
  • Compiler version: Xcode 16.1 Clang and GCC 14.1

Observed Behavior

parallel_for_each "loses" the writable reference to elements in a zip_view, in contrast to std::ranges::for_each, as demonstrated in this program:

#include <ranges>
#include <vector>
#include <iostream>
#include <algorithm>

#include <tbb/parallel_for_each.h>

int main()
{
    const std::vector<int> ints{1,2,3};
    const std::vector<double> doubles{0.1, 0.2, 0.3};

    const auto multiply = [](auto&& intDoubleProduct)
    {
        auto&& [i, d, product] = intDoubleProduct;
        product = i * d;
    };

    {
        std::vector<double> product = {0, 0, 0};
        std::ranges::for_each(std::views::zip(ints, doubles, product), multiply);
        std::cout << "std::ranges::for_each result: (";
        for(auto value : product)
            std::cout << value << ", ";
        std::cout << '\n';
    }
    {
        std::vector<double> product = {0, 0, 0};
        tbb::parallel_for_each(std::views::zip(ints, doubles, product), multiply);
        std::cout << "tbb::parallel_for_each result: (";
        for(auto value : product)
            std::cout << value << ", ";
        std::cout << '\n';
    }
}

https://godbolt.org/z/EvMWGsTP5

Expected Behavior

parallel_for_each writes to the elements in the zipped vector and matches the outcome of std::ranges::for_each.
TBB should be "smarter" about the range it's passed, the core issue seems to be what is described in this StackOverflow answer: https://stackoverflow.com/a/79451943/256138

Note the above example is simple, and the zip_view is passed directly to tbb::parallel_for_each. This case, as described in the comments to that SO answer, can be rewritten to function correctly with a proper wrapper. Unfortunately that inhibits further "range" operations such as std::views::filter, e.g.

const auto is_even = [](const auto& intDoubleProduct) { return std::get<0>(intDoubleProduct) % 2 == 0; };
tbb::parallel_for_each(std::views::zip(ints, doubles, product) | std::views::filter(is_even), multiply);

Which may also change the range/view type that TBB sees in some way (although piping through std::views::all did nothing beneficial to the original issue.

Steps To Reproduce

See code above.

@rubenvb rubenvb added the bug label Feb 20, 2025
@rubenvb rubenvb changed the title Unexpected result with zip_view and parallel_for_each Unexpected result with read/write zip_view and parallel_for_each Feb 20, 2025
@kboyarinov kboyarinov self-assigned this Feb 20, 2025
@kboyarinov
Copy link
Contributor

@rubenvb,

Prior to oneTBB 2021.12, parallel_for_each contained an issue while working with C++20 iterators (including iterators of ranges).
It was fixed by de0a3a6
Consider updating the TBB version you use to at least oneTBB 2021.12 to get the fix.
I have tried locally and it fixed the code snippet you provided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants