Eliminar el puntero a veces resulta en corrupción del montón

Tengo una aplicación multiproceso que se ejecuta utilizando una clase de grupo de subprocesos personalizados. Todos los hilos ejecutan la misma función, con diferentes parámetros.

Estos parámetros se asignan a la clase de subprocesos de la siguiente manera:

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

Tan pronto como un hilo no tiene nada que hacer, obtiene los siguientes parámetros y ejecuta la función de trabajo. Decidí encargarme de la eliminación de los parámetros en la clase de subprocesos:

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

Sin embargo, al hacerlo, a veces me sale un error de corrupción del montón:

Dirección no válida especificada para RtlFreeHeap

Lo extraño es que en un caso funciona perfectamente, pero en otro programa se bloquea con este error. Intenté eliminar el puntero en otros lugares: en el hilo después de la ejecución de la función de trabajo (me aparece el mismo error de corrupción del montón) o al final de la función de trabajo en sí (no hay error en este caso).

No entiendo cómo eliminar los mismos punteros (verifiqué, las direcciones son las mismas) de diferentes lugares cambia nada. ¿Tiene esto algo que ver con el hecho de que es multiproceso?

Tengo una sección crítica que maneja el acceso a los parámetros. No creo que el problema sea sobre el acceso sincronizado. De todos modos, solo se llama al destructor una vez que se han completado todos los subprocesos, y no borro ningún puntero en ningún otro lugar. ¿Se puede borrar el puntero automáticamente?

En cuanto a mi código. La lista de trabajos es una cola de una estructura, compuesta por el ID de un trabajo (que se usa para poder obtener el resultado de un trabajo específico más adelante) y los parámetros.

getNextJob() es llamado por los hilos (tienen un puntero al ThreadPool) cada vez que terminan para ejecutar su último trabajo.

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

Respuestas a la pregunta(7)

Su respuesta a la pregunta