2010-12-21 11 views
6

Bien, estoy preguntando lo mismo que this deleted question, pero lo estoy preguntando más directamente.¿Cómo puedo cambiar de forma atómica dos punteros en Windows?

Tengo dos variables de puntero en dos instancias de la misma clase. Me gustaría intercambiar los contenidos de esas variables (no a qué apuntan, solo las variables mismas) atómicamente.

Me gustaría evitar bloqueos si es posible.

¿Cómo puedo hacer esto?

EDIT: A las tres trillizas respuestas "InterlockedExchangePointer", lea primero el MSDN docs. InterlockedExchangePointer intercambia el valor de un puntero con un valor de en el registro de la pila. (Por sí solo) no intercambia dos punteros en ubicaciones de memoria.

+7

No creo que haya una instrucción X86 sin bloqueo para intercambiar el contenido de dos direcciones de memoria. Sin soporte de la CPU, sería difícil implementar dicha función. ¿Hay alguna garantía sobre los indicadores? (Por ejemplo, ¿están siempre adyacentes en la memoria? En ese caso, podría usar una comparación/cambio de 8 bytes o de 16 bytes en un bucle). –

+0

@James: ya que publicó lo mismo en el comentario de todos: 'int * p1 = algún valor; int * p2 = someothervalue; p2 = InterlockedExchangePointer (p1, p2); 'haría exactamente eso. Aunque, debajo, usa una sección crítica, así que no estoy seguro de que coincida con la necesidad de evitar bloqueos por completo. –

+1

wow, mucha gente dando la respuesta incorrecta ...esto debería ser una pregunta de entrevista ':-)' – rubenvb

Respuesta

13

Voy a dar un paso en falso y decir que usted necesita un candado y que no existe una solución de cierre general para este problema.

Debería leer desde dos direcciones y escribir de nuevo a ambas direcciones de forma atómica. Según mi leal saber y entender, X86 solo puede intercambiar datos atómicamente desde una sola dirección de memoria y un registro. No creo que sea posible intercambiar el contenido de dos direcciones de memoria.

Si puede poner restricciones sobre dónde están los punteros, puede hacerlo. Por ejemplo, si puede garantizar que los punteros están adyacentes en la memoria, puede usar una comparación/intercambio de 64 o 128 bits en un ciclo.

Puede haber soluciones para otros casos simples, pero no creo que vaya a encontrar una solución sin cerraduras para el caso general.

+0

+1 - parece que no hay seguridad de thread 'WindowsApi :: AutoArray :: Swap' para mí. (¡porque cada puntero NO justifica la sobrecarga de mantener una sección crítica!) –

+1

+1 Creo que esto es correcto. –

+0

Una selección limitada de procesadores tiene una operación doble de comparación e intercambio (DCAS/CAS2). También puede usar CMPXCHG16B (doble ancho) para un efecto similar. Esto no es "general", ya que muchas CPU no admiten estas instrucciones, pero se pueden hacer las que sí lo hacen. DCAS está en motorola 68k, CMPXCHG16B está en Intel de 64 bits y * más nuevo * AMD de 64 bits, pero no en versiones anteriores. _InterlockedCompareExchange128 implementa esto como una matriz de punteros de 64 bits evaluados como un campo atómico de 128 bits, pero explotará si el procesador no admite la instrucción. – Lisa

-2

Compruebe las instrucciones xchg del procesador x86 si hacen lo que desea, luego puede envolverlas en la función de ensamblaje en línea. Se garantiza que todas las instrucciones del procesador son atómicas.

+0

Esta respuesta tiene los mismos problemas que las respuestas InterlockedExchangePointer. –

+0

+1 porque * if * in * si hacen lo que desean * devuelve false, por lo tanto, no encontrará una forma simple de hacerlo –

+0

@Pete: * Si * ese "if" devuelve false, entonces este No respondo mi pregunta, incluso si no es objetivamente incorrecta. –

2

Está buscando una versión atómica con enclavamiento de swap.

Que yo sepa, no hay forma de hacerlo utilizando solo las primitivas API de Windows y sin bloqueo explícito. Las diversas funciones Interlocked recomendadas por otros no funcionarán porque solo se cambia uno de los parámetros pasados. Quieres cambiarlos a los dos.

También podría señalar que las funciones Interlocked solo están enclavadas una con respecto a la otra. Si tiene otro código que actualiza uno de estos indicadores pero no usa Interlocked, su código ya no es seguro. Estoy seguro de que te das cuenta de esto, pero pensé que lo mencionaría.

Por lo que yo sé, necesitarás usar una biblioteca o escribir tu propio código para manejar esto.

Cuestiones relacionadas