返回时双重免费或腐败(退出)

时间:2015-06-17 17:53:18

标签: c++ multithreading

我正在进行涉及使用线程计算pi的任务。我使用互斥锁完成了这项工作并且工作正常,但我希望这个版本能够正常工作。这是我的代码。

#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;
}

在大多数情况下,代码工作正常。某些参数组合导致我在return 0上获得双重释放或损坏错误。例如,如果我使用参数10010,程序会创建10个线程并在每个线程上执行10次迭代,工作正常。如果我使用参数104,程序将创建4个线程,在3个线程上执行2次迭代,在第4个线程上执行4次,运行正常。但是,如果我使用53,程序将正确计算值,甚至打印出来,但我会立即得到错误。 173以及103也会发生这种情况。我尝试了157,但是当线程尝试加入时我遇到了munmap_chunk(): invalid pointer错误 - 尽管我认为这是另一个问题。

如果我不得不猜测,它与pthread_exit解除分配内存有关,然后尝试在return上再次释放相同的内存,因为我将参数struct作为传递给一个指针。我尝试了一些不同的东西,比如创建本地副本并将parameterList定义为指针向量,但它没有解决任何问题。我还在erase之前尝试了clearreturn向量,但这也没有帮助。

2 个答案:

答案 0 :(得分:3)

我看到了这个问题:

你的写作超出了矢量界限:

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

访问parameterList[threadCount]超出范围。

我没有在代码中看到threadCount被调整,因此它在整个代码段中保持相同的值。

提示:如果目标是访问容器中的最后一项,请使用vector::back()。它一直适用于非空矢量。

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

答案 1 :(得分:1)

我可以看到的一件事是你可能会超越矢量的末尾:

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

capacity()返回向量可以容纳的元素数量。这可能超过向量的size()。您可以将来电更改为capacity()size(),以确保您不会超越矢量的结尾

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

我发现的第二件事是iterations % threadCount != 0当你有:

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

这是写过矢量的结尾。然后,当您加入所有线程时,您不会像以前一样加入最后一个线程:

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