我正在进行涉及使用线程计算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, ¶meterList[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, ¶meterList[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, ¶meterList[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
上获得双重释放或损坏错误。例如,如果我使用参数100
和10
,程序会创建10个线程并在每个线程上执行10次迭代,工作正常。如果我使用参数10
和4
,程序将创建4个线程,在3个线程上执行2次迭代,在第4个线程上执行4次,运行正常。但是,如果我使用5
和3
,程序将正确计算值,甚至打印出来,但我会立即得到错误。 17
和3
以及10
和3
也会发生这种情况。我尝试了15
和7
,但是当线程尝试加入时我遇到了munmap_chunk(): invalid pointer
错误 - 尽管我认为这是另一个问题。
如果我不得不猜测,它与pthread_exit
解除分配内存有关,然后尝试在return
上再次释放相同的内存,因为我将参数struct作为传递给一个指针。我尝试了一些不同的东西,比如创建本地副本并将parameterList
定义为指针向量,但它没有解决任何问题。我还在erase
之前尝试了clear
和return
向量,但这也没有帮助。
答案 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, ¶meterList[threadCount]);
这是写过矢量的结尾。然后,当您加入所有线程时,您不会像以前一样加入最后一个线程:
for(int i = 0; i < threadCount-1; ++i){
^^^ uh oh. we missed the last thread
pthread_join(threadList[i], &status);
cout << status << endl;
}