La parte más difícil de manejar una sección crítica sin un sistema operativo no es realmente crear el mutex, sino más bien averiguar qué debería pasar si el código quiere usar un recurso que no está disponible actualmente. Las instrucciones de carga exclusiva y de tienda condicional hacen que sea bastante fácil crear una función de "intercambio" que, dado un puntero a un entero, almacenará de forma atómica un nuevo valor, pero devolverá lo que contenía el entero apuntado a:
int32_t atomic_swap(int32_t *dest, int32_t new_value)
{
int32_t old_value;
do
{
old_value = __LDREXW(&dest);
} while(__STREXW(new_value,&dest);
return old_value;
}
Dada una función como la anterior, uno puede ingresar fácilmente una exclusión mutua a través de algo como
if (atomic_swap(&mutex, 1)==0)
{
... do stuff in mutex ... ;
mutex = 0; // Leave mutex
}
else
{
... couldn't get mutex...
}
En ausencia de un sistema operativo, la principal dificultad a menudo reside en el código "no se pudo obtener la exclusión". Si se produce una interrupción cuando un recurso protegido por mutex está ocupado, puede ser necesario que el código de manejo de interrupciones establezca un indicador y guarde alguna información para indicar lo que quería hacer, y luego tenga cualquier código de tipo principal que adquiera el control de exclusión cada vez que se va a liberar la exclusión para ver si una interrupción quería hacer algo mientras se mantenía la exclusión y, si es así, realizar la acción en nombre de la interrupción.
Aunque es posible evitar problemas con las interrupciones que deseen utilizar recursos protegidos por mutex simplemente deshabilitando las interrupciones (y, de hecho, las interrupciones que deshabilitan pueden eliminar la necesidad de cualquier otro tipo de exclusión mutua), en general, es conveniente evitar por más tiempo las deshabilitaciones. de lo necesario.
Un compromiso útil puede ser usar una bandera como se describió anteriormente, pero tener el código de la línea principal que va a liberar las interrupciones de desactivación de exclusión mutua y verificar la bandera antes mencionada (vuelva a habilitar las interrupciones después de liberar la exclusión) ). Este enfoque no requiere dejar las interrupciones deshabilitadas por mucho tiempo, pero protegerá contra la posibilidad de que si el código de la línea principal prueba la bandera de la interrupción después de liberar la exclusión mutua, existe el peligro de que entre el momento en que ve la bandera y el momento actúa sobre él, puede ser reemplazado por otro código que adquiere y libera el mutex y actúa sobre la bandera de interrupción; Si el código de la línea principal no prueba el indicador de la interrupción después de liberar el mutex, una interrupción que ocurre justo antes de que se libere el código de la línea principal, el mutex podría bloquearse pero no ser notada por la línea principal.
En cualquier caso, lo más importante será tener un medio por el cual el código que intenta usar un recurso protegido por mutex cuando no está disponible tendrá un medio de repetir su intento una vez que se libere el recurso.