-4

I am getting a C++ threading error with the below code:

    //create MAX_THREADS arrays for writing data to
thread threads[MAX_THREADS];
char ** data = new char*[MAX_THREADS];
char * currentSlice;
int currentThread = 0;
for (int slice = 0; slice < convertToVoxels(ARM_LENGTH); slice+=MAX_SLICES_PER_THREAD){
    currentThread++;
    fprintf(stderr, "Generating volume for slice %d to %d on thread %d...\n", slice, slice + MAX_SLICES_PER_THREAD >= convertToVoxels(ARM_LENGTH) ? convertToVoxels(ARM_LENGTH) : slice + MAX_SLICES_PER_THREAD, currentThread);

    try {
        //Allocate memory for the slice
        currentSlice = new char[convertToVoxels(ARM_RADIUS) * convertToVoxels(ARM_RADIUS) * MAX_SLICES_PER_THREAD]; 
    } catch (std::bad_alloc&) {
        cout << endl << "Bad alloc" << endl;
        exit(0);
    }
    data[currentThread] = currentSlice;

    //Spawn a thread
    threads[currentThread] = thread(buildDensityModel, slice * MAX_SLICES_PER_THREAD, currentSlice);

    //If the number of threads is maxed out or if we are on the last thread
    if (currentThread == MAX_THREADS || slice + MAX_SLICES_PER_THREAD > convertToVoxels(ARM_LENGTH)){ 
        fprintf(stderr, "Joining threads... \n");

        //Join all threads
        for (int i = 0; i < MAX_THREADS; i++){
            threads[i].join();
        }

        fprintf(stderr, "Writing file chunks... \n");

        FILE* fd = fopen("density.raw", "ab");
        for (int i = 0; i < currentThread; i++){
            fwrite(&data[i], sizeof(char), convertToVoxels(ARM_RADIUS) * convertToVoxels(ARM_RADIUS), fd);
            delete data[i];
        }
        fclose(fd);
        currentThread = 0;
    }
}

The goal of this code is to create smaller sections of a large three dimensional array that can be threaded for increased processing speed, but can also be stitched back together when I write it to a file. To this end I tried to spawn n threads at a time, and after spawning the nth thread join all existing threads, write to the file in question, then reset things and continue the process until all sub problems have been completed.

I am getting the following error:

Generating volume for slice 0 to 230 on thread 1...
Generating volume for slice 230 to 460 on thread 2...
Generating volume for slice 460 to 690 on thread 3...
Generating volume for slice 690 to 920 on thread 4...
Generating volume for slice 920 to 1150 on thread 5...
Generating volume for slice 1150 to 1380 on thread 6...
Generating volume for slice 1380 to 1610 on thread 7...
terminate called without an active exception
Aborted (core dumped)

After doing some research it seems that the issue is I am not joining my threads before they go out of scope. However I thought the code I wrote would do this correctly. Namely this section:

//Join all threads
for (int i = 0; i < MAX_THREADS; i++){
    threads[i].join();
}

Could anyone point out my error (or errors) and explain it a little clearer so I do not repeat the same mistake?

Edit: Note I have verified I am getting into inner if block that is meant to join the threads. After running the file with the thread spawning line and thread joining line commented out I get the following output:

Generating volume for slice 0 to 230 on thread 1...
Generating volume for slice 230 to 460 on thread 2...
Generating volume for slice 460 to 690 on thread 3...
Generating volume for slice 690 to 920 on thread 4...
Generating volume for slice 920 to 1150 on thread 5...
Generating volume for slice 1150 to 1380 on thread 6...
Generating volume for slice 1380 to 1610 on thread 7...
Joining threads and writing file chunk... 
user4581301
  • 33,082
  • 7
  • 33
  • 54
cast2022
  • 13
  • 4
  • As we don't see the output of this line `fprintf(stderr, "Joining threads... \n");` could it be that it's not going into this block and joining the threads? Add a breakpoint on this line and just after the outer loop and see which one get's hit first. – Richard Critten Jul 03 '18 at 17:44
  • This reads like C, not C++. Why no `std::string` or `std::vector`? – alter_igel Jul 03 '18 at 17:45
  • I checked for that, if I commented out the part that spawns the thread, and the part that joins them and just run with the logic to get into that block of code it prints the error message. – cast2022 Jul 03 '18 at 17:46
  • Too many unknowns to provide decent debugging help. My suspicion is you have a hole in `if (currentThread == MAX_THREADS || slice + MAX_SLICES_PER_THREAD > convertToVoxels(ARM_LENGTH))` that allows the program to exit without joining. For example when printing the status you `slice + MAX_SLICES_PER_THREAD >= convertToVoxels(ARM_LENGTH)` but in the joining if you only `slice + MAX_SLICES_PER_THREAD > convertToVoxels(ARM_LENGTH))`. You could be missing the equals case. – user4581301 Jul 03 '18 at 18:18

1 Answers1

0

The issue: you are calling join method for empty thread - you cannot do this, when you call join on non-joinable thread you will get exception.

In this line

thread threads[MAX_THREADS];

you created MAX_THREADS threads using its default constructor. Each thread object after calling default ctor is in non-joinable state. Before calling join you should invoke joinable method, if it returns true you can call join method.

        for (int i = 0; i < MAX_THREADS; i++){
           if(threads[i].joinable())
              threads[i].join();
        }

Now your code crashes when i = 0 because you increment currentThread at the beginning of your for loop:

for (int slice = 0; slice < convertToVoxels(ARM_LENGTH); slice+=MAX_SLICES_PER_THREAD){
  currentThread++; // <---

and you leave threads[0] with empty object while doing this assignment (before first assignment currentThread is 1)

    threads[currentThread] = thread(buildDensityModel, slice * MAX_SLICES_PER_THREAD, currentSlice);
rafix07
  • 20,001
  • 3
  • 20
  • 33