【发布时间】:2010-11-20 13:39:30
【问题描述】:
我有一个使用自定义线程池类运行的多线程应用程序。线程都执行相同的函数,但参数不同。
这些参数通过以下方式提供给线程池类:
// jobParams is a struct of int, double, etc...
jobParams* params = new jobParams;
params.value1 = 2;
params.value2 = 3;
int jobId = 0;
threadPool.addJob(jobId, params);
一旦线程无事可做,它就获取下一个参数并运行作业函数。我决定负责删除线程池类中的参数:
ThreadPool::~ThreadPool() {
for (int i = 0; i < this->jobs.size(); ++i) {
delete this->jobs[i].params;
}
}
但是,这样做时,我有时会收到堆损坏错误:
指定给 RtlFreeHeap 的地址无效
奇怪的是,在一种情况下它可以完美运行,但在另一个程序中它会因为这个错误而崩溃。我尝试在其他地方删除指针:在作业函数执行后的线程中(我得到相同的堆损坏错误)或在作业函数本身的末尾(在这种情况下没有错误)。
我不明白从不同的地方删除相同的指针(我检查过,地址是相同的)会改变什么。这与它是多线程的事实有什么关系吗?
我确实有一个关键部分来处理对参数的访问。我认为问题不在于同步访问。无论如何,只有在所有线程完成后才会调用析构函数,并且我不会在其他任何地方删除任何指针。指针可以自动删除吗?
至于我的代码。作业列表是一个结构的队列,由作业的id(用于以后能够获取特定作业的输出)和参数组成。
getNextJob() 由线程调用(它们有一个指向 ThreadPool 的指针)每次完成执行最后一个作业时。
void ThreadPool::addJob(int jobId, void* params) {
jobData job; // jobData is a simple struct { int, void* }
job.ID = jobId;
job.params = params;
// insert parameters in the list
this->jobs.push(job);
}
jobData* ThreadPool::getNextJob() {
// get the data of the next job
jobData* job = NULL;
// we don't want to start a same job twice,
// so we make sure that we are only one at a time in this part
WaitForSingleObject(this->mutex, INFINITE);
if (!this->jobs.empty())
{
job = &(this->jobs.front());
this->jobs.pop();
}
// we're done with the exclusive part !
ReleaseMutex(this->mutex);
return job;
}
【问题讨论】:
-
在调用 ThreadPool 析构函数之前是否停止所有线程运行?
-
是的,我等到所有线程都完成了。
-
您能否发布更多 ThreadPool 类的源代码,尤其是 addJob?此外,当您的线程“获取下一个参数并运行作业功能”时使用的代码。它对旧参数有什么作用 - 是否释放它们?来源,请!
-
您是否尝试过使用 Valgrind 的 DRD 来查看是否存在导致此问题的同步问题? valgrind.org/docs/manual/drd-manual.html 就此而言,Valgrind 本身会在致命错误实际发生之前查明许多可能破坏堆的错误。 (它的运行速度大约是正常速度的 40 倍。)
-
不幸的是,我在 Windows 下,并且 AFAIK 没有适用于该操作系统的 valgrind 端口。但是,如果您知道类似的(免费)工具,我会非常乐意使用它!
标签: c++ multithreading pointers memory-management heap-corruption