Diferencia entre revisiones de «Cerrojos»
(→Ejemplo de implementación: cero ahora significa libre) |
(corrección de la explicación del ejemplo de implementación de cerrojo) |
||
Línea 15: | Línea 15: | ||
</source> | </source> | ||
− | Sin embargo, esto es problemático: Supongamos que tenemos únicamente un proceso con dos hilos (Hx y Hy) y el planificador retire al hilo Hx justo antes de ejecutarse la instrucción ''cerrojo = | + | Sin embargo, esto es problemático: Supongamos que tenemos únicamente un proceso con dos hilos (Hx y Hy) y el planificador retire al hilo Hx justo antes de ejecutarse la instrucción ''cerrojo = 1;''. El hilo Hy ejecuta su código, entra en la sección crítica (Esto puede ocurrir ya que cerrojo sigue a 0) y el planificador le retira el uso del procesador dentro de ésta. A continuación, se le vuelve a asignar el procesador a Hx. |
De esta forma, tenemos a dos hilos ejecutando código de la sección crítica. Para evitar este problema, debemos implementar los protocolos de entrada y salida de forma que se ejecuten en una sola instrucción, con lo cual o el planificador retira el uso del procesador antes de esta instrucción, o sino lo retira después de haberla ejecutado. | De esta forma, tenemos a dos hilos ejecutando código de la sección crítica. Para evitar este problema, debemos implementar los protocolos de entrada y salida de forma que se ejecuten en una sola instrucción, con lo cual o el planificador retira el uso del procesador antes de esta instrucción, o sino lo retira después de haberla ejecutado. |
Revisión del 21:23 15 nov 2011
Ejemplo de implementación
El siguiente código sería un posible ejemplo del uso de control de concurrencia mediante cerrojos:
int cerrojo = 0; /* Inicializamos la variable cerrojo. Esto sería sólo válido para
hilos, ya que los procesos no comparten espacio de memoria */
while(cerrojo == 1); // Protocolo de
cerrojo = 1; // entrada
... // Sección crítica
cerrojo = 0; // Protocolo de salida
Sin embargo, esto es problemático: Supongamos que tenemos únicamente un proceso con dos hilos (Hx y Hy) y el planificador retire al hilo Hx justo antes de ejecutarse la instrucción cerrojo = 1;. El hilo Hy ejecuta su código, entra en la sección crítica (Esto puede ocurrir ya que cerrojo sigue a 0) y el planificador le retira el uso del procesador dentro de ésta. A continuación, se le vuelve a asignar el procesador a Hx.
De esta forma, tenemos a dos hilos ejecutando código de la sección crítica. Para evitar este problema, debemos implementar los protocolos de entrada y salida de forma que se ejecuten en una sola instrucción, con lo cual o el planificador retira el uso del procesador antes de esta instrucción, o sino lo retira después de haberla ejecutado.
Cerrojos mediante instrucciones atómicas
Podemos implementar cerrojos mediante instrucciones especiales de comprobación y puesta a 0 y 1.
int cerrojo = 0;
void lock() {
while (__sync_lock_test_and_set(&cerrojo, 1));
}
void unlock() {
__sync_lock_release(&cerrojo);
}
El método lock comprueba mediante __sync_locktest_and_set(&cerrojo,1) el valor del cerrojo: si es 0, cambia el valor del cerrojo a 1 y devuelve 0, por tanto, se sale del while y entra en sección crítica; si es 1, devuelve 1 y continúa comprobando el valor, por tanto, no entra en situación crítica hasta que cambie el valor del cerrojo.
El método unlock, mediante _sync_lock_release(&cerrojo), cambia el valor del cerrojo a 0.