OpenMP

OpenMP

At first, I'm sorry for my pour English even I don' know it is right or wrong to question here. But only thing I need is some help.

Now I'm developing stand alone MFC program. So I want to use OpenMP. Then I realized it has some problem or me.

Here is my Test codes. (VC++ 2010 MFC Application - Dialog based Project)

void COpenMPWinDlg::OnBnClickedButton1()
{
    // TODO
    CString sString;
    
    int i=0;
    
    #pragma omp parallel for
    for(i=0; i < 10; i++)
    {
        sString.Format(_T("%d, thread id = %d"), i, omp_get_thread_num());
        //m_List.AddString(sString);
        OutputDebugString(sString + "\r\n");
    }

}

I expected serial number not 0 to 9 (2,3,5,1 ~ 9)

But the result is belows,

0, thread id = 0
1, thread id = 0
1, thread id = 0

2, thread id = 0
7, thread id = 2
8, thread id = 3
8, thread id = 3

4, thread id = 1
9, thread id = 3
5, thread id = 1

I tried it console program in VC++ 2010 then it is working correctly.

But I need it in MFC application. Please help. thank you.

6 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

As far as I understand your question you are expecting linearly increasing loop counter variable i=0, i=1,1=2,1=3 etc... In your case different threads are executing omp region in random order which is chosen probably by the Windows scheduler/dispatcher.

Parallel code, a loop in this example, run in parallel (to the extent of your thread pool size). The parallel part runs concurrently, but not necessarily in sequence.

Your code has an error in that sString is place outside the scope of the parallel region and thus defaults to shared. All threads will attempt to use this string without regard to the other threads. You should also get into the habit of using "for(int i=0;..." to assure that i is private. Note, while OpenMP will automatically make the loop control variable private of a parallel for (or omp for in parallel region), it will not automatically make private loop control variables used on interior loops inside the parallel region.

If you require the output sequence to be in the same order as appears in the serial implementation, then you have two options:

1) Use an output array, not a non-thread safe std::container such as a list, which may get corrupted with concurrent AddString, and in any event will get appended in thread entry order and not necessarily loop index order. The parallel loop would execute in any order with each thread placing its output into the output array. Then after the parallel loop, you would have a serial section performing the in-order output. This procedure would not be practical for high iteration counts.

2) Write your own sequencer. This may also require a schedule modifier to the parallel for to set the chunk size to 1. This would cause thread picking order to be in sequence, however the time of thread completing the computation section and arriving at your output section is not controllable. The usual way to sequence the output then would be with use of a volatile or atomic variable that states the sequence number of the next output. Then threads reaching the output section would loop waiting for the sequence number of the next output to become the value of its index. At which point the thread exits the wait loop, writes its output, increments the next output sequence number, then reaches the bottom of your parallel for loop (and presumably loops back up for another iteration). There are some trade-offs here as the threads are non-productive while they are awaiting their turn to write its output. There are more complicated ways to correct for this.

Jim Dempsey

void COpenMPWinDlg::OnBnClickedButton1()
 {
     // TODO
     CString sString[10]; // same size as loop count
     
     #pragma omp parallel for
     for(int i=0; i < 10; i++)
     {
         // Do work here
         // ...
         // Now output to in-sequence output array
         sString[i].Format(_T("%d, thread id = %d"), i, omp_get_thread_num());
     }
     // after parallel loop, serialy handle output (in sequence)
     for(int i=0; i < 10; i++)
     {
         OutputDebugString(sString[i] + "\r\n");
     }

}

void COpenMPWinDlg::OnBnClickedButton1()
 {
     // TODO
     
     volatile int OutputSequence = 0;
     
     #pragma omp parallel for schedule(dynamic,1)
     for(int i=0; i < BigLoopCount; i++)
     {
         // Do work here
         // ...
         // Now buile output
         CString sString;
         sString.Format(_T("%d, thread id = %d"), i, omp_get_thread_num());
         // wait my turn
         for(;i < OutputSequence;)
           Sleep(0);
         OutputDebugString(sString + "\r\n");
         OutputSequence = i+1; // indicate next ouput sequence number
     }

}

Jim Dempsey

Thank you so much. Now I got the concept. The key was put CString in parellel for. It is really helpful.

Have a good day.

>>I expected serial number not 0 to 9 (2,3,5,1 ~ 9)
>>
>>But the result is belows,
>>
>>0, thread id = 0
>>1, thread id = 0
>>1, thread id = 0
>>2, thread id = 0
>>7, thread id = 2
>>8, thread id = 3
>>8, thread id = 3
>>4, thread id = 1
>>9, thread id = 3
>>5, thread id = 1

The order of calls to OpenMP threads are always Non deterministic and even if your test case outputs could be ordered for Microsoft C++ compiler they could be unordered in case of compilation with a different C++ compiler which supports OpenMP. That is, results with Intel C++ compiler could be different! I've never tried to rely on ordered execution of Open MP threads.

Leave a Comment

Please sign in to add a comment. Not a member? Join today