我有一个使用自定义线程池类运行的多线程应用程序。线程都执行相同的函数,但参数不同。
这些参数通过以下方式提供给线程池类:
// 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;
}