这个问题是对this one的一种改进,它与预期的方向不同。
在我的多线程应用程序中,主线程创建参数并存储它们:
typedef struct {
int parameter1;
double parameter2;
float* parameter3;
} jobParams;
typedef struct {
int ID;
void* params;
} jobData;
std::vector<jobData> jobs;
// main thread
for (int i = 0; i < nbJobs; ++i) {
jobParams* p = new jobParams;
// fill and store params
jobData data;
data.ID = i;
data.params = p;
jobs.push_back(data);
}
// start threads and wait for their execution
// delete parameters
for (int i = 0; i < jobs.size(); ++i) {
delete jobs[i].params;
}
然后,每个线程获得一个指向一组参数的指针,并用它调用一个作业函数:
// thread (generic for any job function and any type of params)
jobData* job = main->getNextParams();
jobFunction(job->ID, job->params);
整个事情采用void *作为参数,以便能够使用参数的任何结构,但然后作业函数将其转换回正确的结构:
void* jobFunction(void* param) {
jobParams* params = (jobParams*) param;
// do stuff
return 0;
}
我的问题如下:如果我在delete params
结束时jobFunction()
,则效果非常好。但是,我宁愿让线程或主线程删除删除,这样我就不必记住删除我写的每个jobFunction()
的参数。
如果我在确认所有线程都已完成后(或因此不再需要参数)之后在踏板中调用delete params
之后尝试jobFunction()
,或者甚至在主线程中尝试{{1}}得到堆损坏错误:
HEAP [prog]:为RtlFreeHeap(02E90000,03C2EE38)指定的无效地址
我正在使用Visual Studio 2008 Pro,因此我无法使用valgrind或其他* nix工具进行调试。从“子线程”对主线程的所有访问都是使用互斥锁同步的,所以问题不在于我删除了两次相同的参数。
事实上,通过使用VS内存查看器,我知道jobParams指针所指向的内存在jobFunction()的结尾和我尝试删除它的位置之间没有变化(在主线程中或在主线程中) “子线程”)。
我添加了两种结构的定义,以及我想删除params的方式。
答案 0 :(得分:2)
就像一个想法......你能试试吗
for (int i = 0; i < jobs.size(); ++i) {
delete (jobParams*)jobs[i].params;
}
新建一个类型的jobParams然后删除一个void *可能是你的问题的原因。
有没有理由将params存储为jobData中的void *?我认为,如果你希望有不同类型的jobParams,那么你应该使用继承层次结构,而不是盲目地转向虚空*。
答案 1 :(得分:1)
这种错误通常意味着你在某处有数据竞争。 main-&gt; getNextParams()是否做正确的事情,即使它被多个线程一次调用?如果它给两者都提供相同的参数,你可以手上有双倍的免费。
此外,而不是
jobFunction(jobData->ID, jobData->params);
你可能意味着
jobFunction(job->ID, job->params);
答案 2 :(得分:1)
要调试它,您可以将deleted
成员添加到jobParams
类,并将其设置为true
,而不是实际删除该对象。然后查看deleted
的每个方法中的jobParams
标志,如果是,则抛出异常。然后看看抛出异常的位置。