EN VI

C++ - Result suddenly wrong when running program on a big number of threads; threads getting called after WaitForMultipleObjects ends?

2024-03-13 17:30:06
C++ - Result suddenly wrong when running program on a big number of threads; threads getting called after WaitForMultipleObjects ends

I have an assignment to split a simple addition cycle (i++ 100000000 times, basically) into multiple threads and time them to see how the performance changes. My code works fine when the number of threads is below 100, but after 100 threads it starts producing completely bogus results. I tried printing the output of every thread to pinpoint the problem, and most of them returned 0. I then added an id parameter to each thread for them to print when they were called, and it turned out that once there were more than 100 threads some didn't get called at all, and some were called after WaitForMultipleObjects should have caught them. My guess would be that it times out, but it's set to INFINITE.

Here's the code:

#include <windows.h>
#include <iostream> 
using namespace std;
#include <stdio.h>
#include <cmath>

DWORD WINAPI fun(LPVOID lpParam);
typedef struct segm {
    int start;
    int stop;
    double res;
    int id;
}*PSEGM;

DWORD   thrID[500];
HANDLE  handles[500];
int m = 100000000;
int n;
double res;

int ns[25] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
              16,20,30,40,50,100,200,300,400,500 };

DWORD WINAPI fun(LPVOID lpParam) {
    PSEGM ps;
    ps = (PSEGM)lpParam;
    printf("%d ", ps->id);
    for (int i = ps->start; i < ps->stop; i++) {
        ps->res += 1;
    }
    return 0;
}

struct segm sa[500];
int main()
{
    for (int i = 0; i < 25; i++) {
        n = ns[i];
        int step = m / n;
        res = 0;
        printf("\n\ni=%d; n=%d;", i,n);
        for (int k = 0; k < n; k++) {
            sa[k].start = k * step + 1;
            sa[k].stop = (k + 1) * step;
            sa[k].res = 0;
            sa[k].id = k; 
        }
        sa[0].start = 0;
        sa[n - 1].stop = m;
       
        for (int k = 0; k < n; k++) {
            handles[k] = CreateThread(NULL,0,fun, &sa[k],0,&thrID[k]);
            if (handles[k] == NULL){ ExitProcess(3);}
        }
        WaitForMultipleObjects(n, handles, TRUE, INFINITE);
        for (int k = 0; k < n; k++){
            res += sa[k].res;
            CloseHandle(handles[k]);
            //printf("%d:%2.4f ", k, sa[k].res);
        }
        printf("total: ");
        cout << res;

    }    
}

An example of a normal and bogus output (I removed the timing stuff from the example for brevity):

i=19; n=50;0 1 2 3 6 5 8 4 7 12 16 14 20 18 25 26 9 10 11 13 15 17 34 19 36 22 23 38 27 40 41 42 43 44 33 35 45 37 24 47 28 48 30 31 49 32 21 46 39 29 time: 0.0410; total: 1e+08

i=20; n=100;0 3 4 1 5 6 7 9 2 8 10 13 12 20 14 15 11 18 21 16 17 37 19 41 22 23 24 25 26 27 28 29 30 34 35 39 74 75 time: 0.0280; total: 3.4e+0731 40 32 76 33 42 46 47 48 49 98 84 43 53 54 55 56 58 57 59

I am also getting these two warnings: Using uninitialized memory 'handles[BYTE:0]' and Buffer overrun while writing to 'sa'. I don't see how I could have a buffer overrun; I tried making sa bigger, but the warning didn't go away. I think I've initialized everything, too. I don't know if these things are related to the error, though.

I'm really stuck and confused and would appreciate any help. Thanks!

Solution:

WaitForMultipleObjects can only wait on a maximum of MAXIMUM_WAIT_OBJECTS (which is 64) handles. As soon as you try to wait on more handles which is the case in your code, the wait fails and therefore your output is garbage.

If you want to wait on more than MAXIMUM_WAIT_OBJECTS handles, you need to figure out something else, maybe like dividing your handles in batches of at most MAXIMUM_WAIT_OBJECTS handles and waiting on each batch separately.

Change your code like this, run it and you'll see what happens:

    auto r = WaitForMultipleObjects(n, handles, TRUE, INFINITE);
    if (r != 0)
    {
      printf("WaitForMultipleObjects failed, last error = %d\N", GetLastError());
      return 3;
    }
Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login