Das Löschen eines Zeigers führt manchmal zu einer Beschädigung des Heapspeichers

Ich habe eine Multithread-Anwendung, die mit einer benutzerdefinierten Thread-Pool-Klasse ausgeführt wird. Die Threads führen alle dieselbe Funktion mit unterschiedlichen Parametern aus.

Diese Parameter werden der Threadpool-Klasse folgendermaßen übergeben:

// 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);

Sobald ein Thread nichts mehr zu tun hat, ruft er die nächsten Parameter ab und führt die Jobfunktion aus. Ich habe beschlossen, die Parameter in der Threadpool-Klasse zu löschen:

ThreadPool::~ThreadPool() {
    for (int i = 0; i < this->jobs.size(); ++i) {
        delete this->jobs[i].params;
    }
}

Dabei erhalte ich jedoch manchmal einen Heap-Korruptionsfehler:

Ungültige Adresse für RtlFreeHeap angegeben

Das Seltsame ist, dass es in einem Fall perfekt funktioniert, in einem anderen Programm jedoch mit diesem Fehler abstürzt. Ich habe versucht, den Zeiger an anderen Stellen zu löschen: im Thread nach der Ausführung der Jobfunktion (ich erhalte den gleichen Heap-Korruptionsfehler) oder am Ende der Jobfunktion selbst (in diesem Fall kein Fehler).

Ich verstehe nicht, wie das Löschen der gleichen Zeiger (ich habe geprüft, die Adressen sind die gleichen) von verschiedenen Stellen etwas ändert. Hat dies etwas mit der Tatsache zu tun, dass es sich um Multithreading handelt?

Ich habe einen kritischen Abschnitt, der den Zugriff auf die Parameter behandelt. Ich glaube nicht, dass es sich bei dem Problem um einen synchronisierten Zugriff handelt. Wie auch immer, der Destruktor wird nur aufgerufen, wenn alle Threads fertig sind, und ich lösche nirgendwo anders einen Zeiger. Kann der Zeiger automatisch gelöscht werden?

Wie für meinen Code. Die Liste der Jobs ist eine Warteschlange einer Struktur, die sich aus der ID eines Jobs (um später die Ausgabe eines bestimmten Jobs zu erhalten) und den Parametern zusammensetzt.

getNextJob() wird jedes Mal von den Threads aufgerufen (sie haben einen Zeiger auf den ThreadPool), wenn sie mit der Ausführung ihres letzten Jobs fertig sind.

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;
}

Antworten auf die Frage(7)

Ihre Antwort auf die Frage