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:
07: using namespace tbb; 36: int main() { 50: return 0; 51: }
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: }
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 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: }
At runtime, the template parallel_for automatically divides the range into subranges and invokes the SubStringFinder function object on each 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