简体   繁体   中英

Double free or corruption (out) on return

I'm doing an assignment that involves calculating pi with threads. I've done this using mutex and it works fine, but I would like to get this version working as well. Here is my code.

#include <iostream>
#include <stdlib.h>
#include <iomanip>
#include <vector>
#include <pthread.h>

using namespace std;

typedef struct{
    int iterations;     //How many iterations this thread is going to do
    int offset;         //The offset multiplier for the calculations (Makes sure each thread calculates a different part of the formula)
}threadParameterList;

vector<double> partialSumList;

void* pi_calc(void* param){
    threadParameterList* _param = static_cast<threadParameterList*>(param);
    double k = 1.0;
    for(int i = _param->iterations * _param->offset + 1; i < _param->iterations * (_param->offset + 1); ++i){
        partialSumList[_param->offset] += (double)k*(4.0/((2.0*i)*(2.0*i+1.0)*(2.0*i+2.0))); 
        k *= -1.0;
    }
    pthread_exit(0);
}

int main(int argc, char* argv[]){

    //Error checking
    if(argc != 3){
        cout << "error: two parameters required [iterations][threadcount]" << endl;
        return -1;
    }
    if(atoi(argv[1]) <= 0 || atoi(argv[2]) <= 0){
        cout << "error: invalid parameter supplied - parameters must be > 0." << endl;
        return -1;
    }

    partialSumList.resize(atoi(argv[2]));

    vector<pthread_t>           threadList    (atoi(argv[2]));
    vector<threadParameterList> parameterList (atoi(argv[2]));

    int iterations  = atoi(argv[1]),
        threadCount = atoi(argv[2]);

    //Calculate workload for each thread
    if(iterations % threadCount == 0){  //Threads divide evenly
        for(int i = 0; i < threadCount; ++i){
            parameterList[i].iterations = iterations/threadCount;
            parameterList[i].offset = i;
            pthread_create(&threadList[i], NULL, pi_calc, &parameterList[i]);
        }
        void* status;
        for(int i = 0; i < threadCount; ++i){
            pthread_join(threadList[i], &status);
        }

    }
    else{                               //Threads do not divide evenly
        for(int i = 0; i < threadCount - 1; ++i){
            parameterList[i].iterations = iterations/threadCount;
            parameterList[i].offset = i;
            pthread_create(&threadList[i], NULL, pi_calc, &parameterList[i]);
        }
        //Add the remainder to the last thread
        parameterList[threadCount].iterations = (iterations % threadCount) + (iterations / threadCount);
        parameterList[threadCount].offset = threadCount - 1;
        pthread_create(&threadList[threadCount], NULL, pi_calc, &parameterList[threadCount]);
        void* status;
        for(int i = 0; i < threadCount-1; ++i){
            pthread_join(threadList[i], &status);
            cout << status << endl;
        }
    }

    //calculate pi
    double pi = 3.0;
    for(int i = 0; i < partialSumList.size(); ++i){
        pi += partialSumList[i];
    }

    cout << "Value of pi: " << setw(15) << setprecision(15) << pi << endl;

    return 0;
}

The code works fine in most cases. There are certain combinations of parameters that cause me to get a double free or corruption error on return 0 . For example, if I use the parameters 100 and 10 the program creates 10 threads and does 10 iterations of the formula on each thread, works fine. If I use the parameters 10 and 4 the program creates 4 threads that do 2 iterations on 3 threads and 4 on the 4th thread, works fine. However, if I use 5 and 3 , the program will correctly calculate the value and even print it out, but I get the error immediately after. This also happens for 17 and 3 , and 10 and 3 . I tried 15 and 7 , but then I get a munmap_chunk(): invalid pointer error when the threads are trying to be joined - although i think that's something for another question.

If I had to guess, it has something to do with pthread_exit deallocating memory and then the same memory trying to be deallocated again on return , since I'm passing the parameter struct as a pointer. I tried a few different things like creating a local copy and defining parameterList as a vector of pointers, but it didn't solve anything. I've also tried erase ing and clear ing the vector before return but that didn't help either.

I see this issue:

You are writing beyond the vector's bounds:

    vector<threadParameterList> parameterList (atoi(argv[2]));
    //...
    int        threadCount = atoi(argv[2]);
    //...
    parameterList[threadCount].iterations = (iterations % threadCount) + (iterations / threadCount);
    parameterList[threadCount].offset = threadCount - 1;

Accessing parameterList[threadCount] is out of bounds.

I don't see in the code where threadCount is adjusted, so it remains the same value throughout that snippet.

Tip: If the goal is to access the last item in a container, use vector::back() . It works all the time for non-empty vectors.

    parameterList.back().iterations = (iterations % threadCount) + (iterations / threadCount);
    parameterList.back().offset = threadCount - 1;

One thing I can see is you might be going past the end of the vector here:

for(int i = 0; i < partialSumList.capacity(); ++i)

capacity() returns how many elements the vector can hold. This can be more than the size() of the vector. You can change you call to capacity() to size() to make sure you don't go past the end of the vector

for(int i = 0; i < partialSumList.size(); ++i)

The second thing I spot is that when iterations % threadCount != 0 you have:

parameterList[threadCount].iterations = (iterations % threadCount) + (iterations / threadCount);
parameterList[threadCount].offset = threadCount - 1;
pthread_create(&threadList[threadCount], NULL, pi_calc, &parameterList[threadCount]);

Which is writing past the end of the vector. Then when you join all of the threads you don't join the last thread as you do:

for(int i = 0; i < threadCount-1; ++i){
                              ^^^ uh oh.  we missed the last thread 
    pthread_join(threadList[i], &status);
    cout << status << endl;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM