2009-04-27 17 views
5

He estado profundizando en C++ recientemente y mis errores parecen ser complejos.C++: ¿Cómo es posible que la lectura de datos pueda afectar la memoria?

Tengo un vector de objetos, cada objeto contiene un vector de flotadores. Decidí que necesitaba crear una matriz plana adicional que contenga todos los valores flotantes de todos los objetos en uno. Es un poco más complejo que eso, pero la esencia del problema es que a medida que recorro mis objetos extrayendo los valores float, en algún momento mi vector de objetos cambia o se corrompe de alguna extraña manera. (Mis operaciones de lectura son todas funciones const)

Otro ejemplo fue con MPI. Acababa de comenzar, así que solo quería ejecutar exactamente el mismo código en dos nodos diferentes con su propia memoria y sin transferencia de datos, todo muy simple. Para mi sorpresa obtuve errores de segmentación y seguimiento después de horas, encontré que una asignación de una variable establecía una variable completamente diferente a NULL.

Así que tengo curiosidad, ¿cómo es posible que las operaciones de lectura puedan afectar a mis estructuras de datos? Del mismo modo, ¿cómo puede una operación aparentemente no relacionada afectar a otra. No podría esperar soluciones a mis problemas con esas breves descripciones, pero cualquier consejo será muy apreciado.

Actualización: Aquí hay un segmento del código, no publiqué originalmente porque no estoy seguro de cuánto se puede extraer sin entender todo el sistema.

Una cosa que acabo de descubrir es que cuando dejé de asignar el valor a mi matriz plana y simplemente cout'ed en su lugar, desaparecieron los errores seg. Así que tal vez estoy declarando mi arreglo incorrecto, pero incluso si lo fuera, no estoy seguro de cómo afectaría el vector objeto.

void xlMasterSlaveGpuEA::FillFlatGenes() { 
    int stringLength = pop->GetGenome(0).GetLength(); 
    for (int i=0;i<pop->GetPopSize();i++) 
     for (int j=0;j<stringLength;j++) 
      flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 
} 

float xlVectorGenome::GetFloatGene(unsigned int i) const { 
    return GetGene(i); 
} 

mi matriz plana es una función miembro

float * flatFitness; 

initailsed en el constructor de este modo:

flatFitness = new float(popSize); 

Actualización 2:

sólo quiero señalar que la dos ejemplos anteriores no están relacionados, el primero no tiene múltiples hilos. El segundo ejemplo de MPI es técnicamente, pero MPI es memoria distribuida e intenté deliberadamente la implementación más simple que pude pensar, que es ambas máquinas ejecutando código de forma independiente. Sin embargo, hay un detalle adicional, puse en un condtional diciendo

if node 1 then do bottom half of loop 

if node 1 then do top half 

Una vez más la memoria deben ser aislados, deberían estar trabajando como si no saben nada el uno del otro .. pero retirar esta condicional y haciendo ambos bucles hacen todos los cubos, elimina el error

+0

¿Se puede publicar una versión resumida de su código? Desde este punto, es muy difícil saber qué podría estar pasando. – tgamblin

+0

¿Podría publicar el código del bucle en el que itera los objetos en el vector ... posiblemente está caminando sobre la memoria allí? – Balk

+1

Las operaciones de lectura no cambian los valores. Debe haber algo más en tu código. Su segundo ejemplo es una situación típica de una variable que apunta al lugar equivocado. – fbinder

Respuesta

14

Esto no es un constructor array:

float * flatFitness; 
flatFitness = new float(popSize); 

Está creando un flotador en el montón aquí, inicializado con el valor popSize. Si quieres una serie de flotadores es necesario utilizar soportes en lugar de paréntesis:

float *flatFitness = new float[popSize]; 

Esto fácilmente podría ser la causa de los problemas que usted describe. Además, recuerda al crear matrices, es necesario eliminar el uso de delete [] (con el tiempo):

delete [] flatFitness; 

Si sólo utiliza delete, podría funcionar, pero el comportamiento no está definido.

Si desea evitar el uso de la sintaxis de matriz por completo, ¿por qué no utilizar std::vector? Puede crear un vector de elementos POPSIZE así:

#include <vector> 

std::vector<float> flatFitness(popSize); 

Esto se libera automáticamente cuando esté fuera de su alcance, por lo que no tiene que preocuparse de new o delete.

Update (re: comentario): Si ya está utilizando std::vectors en otras partes de su código, echar un vistazo a std::vector::swap(). Es posible que pueda evitar copiar cosas por completo y simplemente intercambie un par de vectores hacia adelante y hacia atrás entre el almacenamiento en búfer de CUDA y el procesamiento que está haciendo aquí.

+0

gracias, lo comprobaré – zenna

+0

curiosamente estoy extrayendo los datos de std :: vectores ya que necesito enviarlos a la GPU a través de CUDA. Probablemente haya una manera mucho más elegante – zenna

+0

Eche un vistazo a vector :: swap(). Es posible que pueda crear instancias de algunos vectores aquí, luego cambiarlos por los que usa para CUDA para que no tenga que hacer ninguna copia. Solo asegúrate de que tengan el tamaño correcto usando resize() o el constructor (como se muestra arriba), o podrías terminar escribiendo en la memoria que no tienes. – tgamblin

0

Sospecho que tiene problemas de subprocesamiento múltiple o corrupción de memoria que no conoce. El comportamiento que describes no es ningún tipo de comportamiento deseable estándar, por diseño.

+0

Sí, esto suena como un caso casi de libro de texto de barreras de memoria faltantes y sincronización entre hilos insuficiente. Solo se necesita un hilo para actualizar el objeto de datos en algún momento después de que sea visible para otro hilo, y la falta de sincronización te morderá tarde o temprano. –

+1

Quizás, excepto que nunca dijo que estaba usando hilos. MPI es un paralelismo a nivel de proceso a menos que lo combines con otra cosa. – tgamblin

+0

Heh, no se publicó ningún código cuando respondí. –

-1

jeffamaphone puede tener razón de que se trata de un problema de subprocesamiento. Otra posibilidad es que los objetos que estás leyendo ya hayan sido eliminados. Entonces estaría leyendo desde una dirección no válida. También es posible que las estructuras de datos en las que está escribiendo en este momento estén almacenadas en la misma ubicación que los vectores anteriormente ocupados. Esto daría como resultado el comportamiento que describes.

EDITAR (basado en la actualización):

Esto puede ser defectuosa: stringLength se inicializa fuera del bucle exterior, pero parece que necesita ser actualizado durante ese lazo externo:

int stringLength = pop->GetGenome(0).GetLength(); 
for (int i=0;i<pop->GetPopSize();i++) 
    for (int j=0;j<stringLength;j++) 
     flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 

solución sugerida:

for (int i=0;i<pop->GetPopSize();i++) { 
    int stringLength = pop->GetGenome(i).GetLength(); 
    for (int j=0;j<stringLength;j++) { 
     flatGenes[(i*stringLength)+j]<< pop->GetGenome(i).GetFloatGene(j); 
    } 
} 
Cuestiones relacionadas