Develop an Application Using parallel_for

This section presents a basic example that uses the parallel_for template in a substring matching program. For each position in a string, the program displays the length and location of the largest matching substring elsewhere in the string.

Consider the string babba as an example. Starting at position 0, ba is the largest substring with a match elsewhere in the string (position 3).

You can refer to a complete version of this program in the Intel® Threading Building Blocks (Intel® TBB) examples/GettingStarted folder. Or you can follow the step-by-step development of this application given here. In this section, new code that is added in each step is shown in bold font. Lines are numbered in the order they appear in the final completed example.

To develop the example code:

  1. Create a new empty application.
  2. The using statement imports the namespace tbb, in which all of the libraries classes and functions are found (line 07).
    07:       using namespace tbb;
            
    36:     int main() {
    50:       return 0;
    51:    }
    
  3. Create the example string that is transformed by the program (lines 38 - 40) and the arrays for holding the lengths of the largest matched substrings and their locations (lines 42 - 43). The example generates a Fibonacci string consisting of a series of a and b characters.
  4. Add statements to output the lengths and locations of the largest substring matches for each position (lines 46 - 47).
    01:      #include <iostream>
    02:     #include <string>        
            
    07:     using namespace tbb;
    08:     using namespace std;
    09:     static const size_t N = 23;
            
    36:     int main() {
            
    38:       string str[N] = { string("a"), string("b") };
    39:       for (size_t i = 2; i < N; ++i) str[i] = str[i-1]+str[i-2];
    40:       string &to_scan = str[N-1]; 
    41:       size_t num_elem = to_scan.size();
            
    42:       size_t *max = new size_t[num_elem];
    43:       size_t *pos = new size_t[num_elem];
            
    44—45:      // add code to populate max and pos here
            
    46:       for (size_t i = 0; i < num_elem; ++i)
    47:         cout << " " << max[i] << "(" << pos[i] << ")" << endl;
    48:       delete[] pos;
    49:       delete[] max;
    50:       return 0;
    51:     }
    
  5. Add a call to the parallel_for template function (lines 44 - 45).

    The first parameter of the call is a blocked_range object that describes the iteration space.

    blocked_range is a template class provided by the Intel TBB library. The constructor takes the following parameters:

    • The lower bound of the range.
    • The upper bound of the range.

    The second parameter to the parallel_for function is the function object to be applied to each subrange.

    01:       #include <iostream>
    02:     #include <string>                                         
    05:     #include "tbb/parallel_for.h"
    06:     #include "tbb/blocked_range.h"
            
    07:     using namespace tbb;
    08:     using namespace std;
    09:     static const size_t N = 23;
            
    36:     int main() {
            
    38:       string str[N] = { string("a"), string("b") };
    39:       for (size_t i = 2; i < N; ++i) str[i] = str[i-1]+str[i-2];
    40:       string &to_scan = str[N-1]; 
            
    41:       size_t num_elem = to_scan.size();
            
    42:       size_t *max = new size_t[num_elem];
    43:       size_t *pos = new size_t[num_elem];
            
    44:       parallel_for(blocked_range<size_t>(0, num_elem ),
    45:                    SubStringFinder( to_scan, max, pos ) );          
            
    46:       for (size_t i = 0; i < num_elem; ++i)
    47:         cout << " " << max[i] << "(" << pos[i] << ")" << endl;
    48:       delete[] pos;
    49:       delete[] max;
    50:       return 0;
    51:     }
    
  6. Implement the body of the parallel_for loop (lines 10 - 35).

    At runtime, the template parallel_for automatically divides the range into subranges and invokes the SubStringFinder function object on each subrange.

  7. Define the class SubStringFinder (line 10) to populate the max and pos array elements found within the given subrange.

    At line 16, the call r.begin() returns the start of the subrange and the r.end() method returns the end of the subrange.

    01:       #include <iostream>
    02:     #include <string>                                         
    03:     #include <algorithm>
    04:     #include "tbb/parallel_for.h"
    05:     #include "tbb/blocked_range.h"
            
    07:     using namespace tbb;
    08:     using namespace std;
    09:     static const size_t N = 23;
            
    10:     class SubStringFinder {        
    11:       const string str;    
    12:       size_t *max_array;
    13:       size_t *pos_array;
    14:    public: 
    15:      void operator() ( const blocked_range<size_t>& r ) const { 
    16:         for ( size_t i = r.begin(); i != r.end(); ++i ) {
    17:           size_t max_size = 0, max_pos = 0;
    18:           for (size_t j = 0; j < str.size(); ++j)
    19:           if (j != i) {    
    20:             size_t limit = str.size()-max(i,j);
    21:             for (size_t k = 0; k < limit; ++k) {
    22:               if (str[i + k] != str[j + k]) break;
    23:               if (k > max_size) {
    24:                 max_size = k;
    25:                 max_pos = j;
    26:               }
    27:             }
    28:          }
    29:           max_array[i] = max_size;
    30:           pos_array[i] = max_pos;
    31:         }
    32:       }
    33:       SubStringFinder(string &s, size_t *m, size_t *p) :
    34:         str(s), max_array(m), pos_array(p) { }
    35:     };
            
    36—51:    // The function main starting at line 36 goes here
    

Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.