カスタム スレッド プール クラスを使用して実行するマルチスレッド アプリケーションがあります。スレッドはすべて、異なるパラメータで同じ関数を実行します。
これらのパラメーターは、次の方法でスレッドプール クラスに与えられます。
// 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;
}