2011-02-08 14 views
5

Existen innumerables preguntas sobre cómo implementar contadores de referencia seguros para subprocesos. Y una respuesta común altamente votada es: "usar incrementos/decrementos atómicos". Ok, esta es una buena forma de leer y escribir refCounter sin otro hilo que lo cambie entre medio. Pero.Otra pregunta sobre el conteo seguro de subprocesos

Mi código es:

void String::Release() 
{ 
    if (0 == AtomicDecrement(&refCounter))) 
     delete buffer; 
} 

So. Decremento y leo refCounter en caja fuerte. Pero ¿y si otro hilo INCREMENTARA mi refCounter mientras lo comparo con cero?

¿Estoy equivocado?

EDIT: (ejemplo)

String* globalString = new String(); // refCount == 1 after that. 

// thread 0: 
delete globalString; 
    // This invokes String::Release(). 
    // After AtomicDecrement() counter becomes zero. 
    // Exactly after atomic decrement current thread switches to thread 1. 

// thread 1: 
String myCopy = *globalString; 
    // This invokes AddRef(); 
    // globalString is alive; 
    // internal buffer is still not deleted but refCounter is zero; 
    // We increment and switch back to thread 0 where buffer will be 
    // succefully deleted; 

¿Me equivoco?

+2

¿Cómo puede otro hilo incrementar el contador si no tiene una referencia al objeto ? Un valor de 0 significa literalmente "no quedan referencias". –

Respuesta

1

Su ejemplo me suena bien.

Sin embargo, aquí no se trata de operaciones atómicas, sino de eliminar manualmente un objeto y luego hacer referencia a un objeto que pronto se eliminará. ¿Qué pasa si el conteo de referencia, en lugar de ser 1, es 8 ?.

Debe evitar borrar e invalidar el objeto manualmente, y utilizar mejor la implementación de algunos punteros inteligentes que tengan en cuenta la concurrencia para manejar el recuento de referencias.

Cada vez que un puntero detecta que el recuento es cero, debe bloquear el objeto para evitar que otro subproceso lo haga referencia, al igual que el double-checked locking para inicializar la nueva referencia.

+2

¿Cómo accedería otro subproceso al objeto, cuando no quedan referencias al objeto? –

+1

@Jeremy, como dijo Anton en el ejemplo de la pregunta, si un hilo llama al método Release() y, justo después de la llamada AtomicDecrement y antes de la instrucción delete, otro hilo intenta adquirir una referencia, el recuento equivaldría a cero, pero el segundo thread obtendría la referencia, incrementando el refcount justo antes de la eliminación, eliminando un objeto con un refcount == 1. Es un caso altamente improbable pero no imposible. – vz0

+0

Gracias personas. En realidad, es un problema para hacer que globalString sea seguro para subprocesos y no el búfer interno. Entonces, como vz0 sugirió, debería bloquear el GlobalString primero antes de intentar trabajar con él. PD String es solo un ejemplo, en mi código real tengo dependencias un poco más complicadas. –

2

¡Cuidado!

No es suficiente proteger una variable como un contador de referencia que gestiona el ciclo de vida de algo más grande.

que he visto un código como el que está en su pregunta que termina muy mal ...

en su caso es no sólo que alguien podría incrementar el contador después de la comparación, pero un poco de hilo puede conseguir el contador con valor 1, entonces decrementas y borrar el buffer de memoria y el otro uso de hilo borrado ... CRASH

MY2C

Cuestiones relacionadas