Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Get container index when using QtConcurrent
Forum Updated to NodeBB v4.3 + New Features

Get container index when using QtConcurrent

Scheduled Pinned Locked Moved General and Desktop
8 Posts 2 Posters 4.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    andre
    wrote on last edited by
    #1

    I was wondering: is it somehow possible to get the index of the item a QtConcurrent::map run is operating on inside the mapping function itself? For instance, for an algorithm I need to fill a large vector with equally spaced values, so basically:
    @
    QVector<double> v(SIZE);
    for (int i(0); i<SIZE; ++i) {
    v[i] = factor * i;
    }
    @

    The above sure works, but I was wondering if I could make use of the multi-core features any modern desktop has, and use QtConcurrent to do the same. All the samples I see operate on the value directly, but in this case the resulting value needs to be dependent on the index of the item, not (only) on the current value.

    I know I could implement a multi-threaded solution manually, but I'm interested to see if I can use the high-level Qt threading primitives for a task like this. Any ideas?

    1 Reply Last reply
    0
    • L Offline
      L Offline
      lgeyer
      wrote on last edited by
      #2

      Well, that's a good question. I understand that there is no index passed to the map function as not every sequence has the concept of an index but it would be cleary of use in such cases.

      You could use the item itself and some pointer arithmetic to calculate its position within the vector.
      @
      void initialize(double &value, double factor, double *base)
      {
      value = factor * (&value - base);
      }

      QVector<double> vector(SIZE);
      double factor = 10;

      QtConcurrent::map(vector, std::bind(initialize, std::placeholders::_1, factor, vector.data()));
      @
      You will most probably sacrifice an unreasonable amount of performance using <code>bind</code> with such a short codepath of just a multiplication. So a version using globals (for <code>factor</code> and <code>base</code>) might perform better - although beeing somewhat ugly.
      @
      namespace Initializer
      {
      double factor;
      double *base;

      void initialize(double &value)
      {
          value = factor * (&value - base);
      }
      

      };

      QVector<double> vector(SIZE);
      Initializer::factor = 10;
      Initializer::base = vector.data();

      QtConcurrent::map(vector, Initializer::initialize);
      @

      1 Reply Last reply
      0
      • A Offline
        A Offline
        andre
        wrote on last edited by
        #3

        Interesting approach! Thanks Lukas!

        I think it is a great idea to use the address of the value, as it is passed by (const) reference. That should work, and it would be easy to extend my functor to use that trick too.

        I looked in the source code of QtConcurrent, and I think it would be doable to create a version where the mapping function takes an iterator to the item, instead of the item itself. That would allow for functions like the above (trivial) one, but also for things like smoothing filters that depend not only on the value of the current position, but on the values surrounding it too.

        1 Reply Last reply
        0
        • L Offline
          L Offline
          lgeyer
          wrote on last edited by
          #4

          You're welcome.

          I'm regularly stretched to QtConcurrents limits when using it (not beeing able to clear a QThreadPools run queue or terminating QRunnables is another nasty, nasty limitation).

          So I'm really looking forward to QtConcurrent contributions ;-)

          1 Reply Last reply
          0
          • A Offline
            A Offline
            andre
            wrote on last edited by
            #5

            During my lunch walk I thought of a possible limitation to this approach: is it guaranteed that an iterator always returns a reference to the actual value in the container? Might an iterator not return a copy instead, for whatever reason? If a copy is returned, the approach with the pointer artithmatic would be quite dangerous, right?

            1 Reply Last reply
            0
            • L Offline
              L Offline
              lgeyer
              wrote on last edited by
              #6

              Well, if a copy is passed to the map function you are de-facto screwed.

              However, I see no reason why there should be a copy passed (in both, the immutable -ed() and the mutable version) as long as the compiler is not forced to create a temporary, for example during an implicit conversion if the sequence item type and the map function item type do not match.

              So, yes, the question is if this behaviour is actually guaranteed (that an iterator must not return a copy during iteration). And honestly, I don't know.

              1 Reply Last reply
              0
              • L Offline
                L Offline
                lgeyer
                wrote on last edited by
                #7

                I've just realized that I totally forgot about another obvious solution, which turned out to be way faster than using <code>bind</code> or a functor and even slightly faster than using globals.
                @
                QVector<double> vector(SIZE);
                double factor = 10;
                double *base = vector.data();

                QtConcurrent::map(vector, [&factor, &base](double &value)
                {
                value = factor * (&value - base);
                });
                @
                Isn't it beautiful? Go C++11 folks!

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  andre
                  wrote on last edited by
                  #8

                  Yes, C++11 is cool for this, but unfortunately my compiler doesn't support these expressions yet. I'd still prefer a version with iterators though, I think:

                  @
                  QVector<double> vector(SIZE);
                  double factor = 10;
                  QVector<double>::iterator begin = vector.begin();

                  QtConcurrent::map(vector, [&factor, begin](QVector<double>::iterator it)
                  {
                  value = factor * (it - begin);
                  });
                  @

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved