Algoritmo de Dekker en Sincronización de Procesos

Requisito previo: sincronización de procesos, comunicación entre procesos 
Para obtener dicha exclusión mutua, espera limitada y progreso, se han implementado varios algoritmos, uno de los cuales es el algoritmo de Dekker. Para comprender el algoritmo, comprendamos primero la solución al problema de la sección crítica. 
Un proceso generalmente se representa como: 
 

do {
    //entry section
        critical section
    //exit section
        remainder section
} while (TRUE);

La solución al problema de la sección crítica debe asegurar las siguientes tres condiciones: 
 

  1. Exclusión mutua
  2. Progreso
  3. Espera limitada

Una de las soluciones para asegurar por encima de todos los factores es la solución de Peterson .
Otra es la Solución de Dekker . El algoritmo de Dekker fue la primera solución probablemente correcta al problema de la sección crítica. Permite que dos subprocesos compartan un recurso de un solo uso sin conflicto, utilizando solo la memoria compartida para la comunicación. Evita la alternancia estricta de un algoritmo ingenuo de toma de turnos y fue uno de los primeros algoritmos de exclusión mutua que se inventaron.
Aunque existen muchas versiones de la Solución de Dekker, la versión final o 5ª es la que cumple todas las condiciones anteriores y es la más eficiente de todas. 
Nota –La solución de Dekker, mencionada aquí, garantiza la exclusión mutua solo entre dos procesos, podría extenderse a más de dos procesos con el uso adecuado de arrays y variables.
Algoritmo: requiere una array de valores booleanos y una variable entera:
 

var flag: array [0..1] of boolean;
turn: 0..1;
repeat

        flag[i] := true;
        while flag[j] do
                if turn = j then
                begin
                        flag[i] := false;
                        while turn = j do no-op;
                        flag[i] := true;
                end;

                critical section

        turn := j;
        flag[i] := false;

                remainder section

until false;

Primera versión de la solución de Dekker: la idea es usar un número de subproceso común o compartido entre procesos y evitar que el otro proceso ingrese a su sección crítica si el subproceso compartido indica que el anterior ya se está ejecutando.
 

CPP

Main()
{
 
    int thread_number = 1;
    startThreads();
}
 
Thread1()
{
    do {
 
        // entry section
        // wait until threadnumber is 1
        while (threadnumber == 2)
            ;
 
        // critical section
 
        // exit section
        // give access to the other thread
        threadnumber = 2;
 
        // remainder section
 
    } while (completed == false)
}
 
Thread2()
{
 
    do {
 
        // entry section
        // wait until threadnumber is 2
        while (threadnumber == 1)
            ;
 
        // critical section
 
        // exit section
        // give access to the other thread
        threadnumber = 1;
 
        // remainder section
 
    } while (completed == false)
}

Python3

def Thread1():
    doWhile=False
    while not completed or not doWhile:
        doWhile=True
        # entry section
        # wait until threadnumber is 1
        while (threadnumber == 2):
            pass
 
        # critical section
 
        # exit section
        # give access to the other thread
        threadnumber = 2
 
        # remainder section
 
def Thread2():
    doWhile=False
    while not completed or not doWhile:
        doWhile=True
        # entry section
        # wait until threadnumber is 2
        while (threadnumber == 1):
            pass
 
        # critical section
 
        # exit section
        # give access to the other thread
        threadnumber = 1
 
        # remainder section
 
if __name__ == '__main__':
 
    thread_number = 1
    startThreads()

El problema que surge en la implementación anterior es la sincronización lockstep, es decir, cada subproceso depende del otro para su ejecución. Si uno de los procesos se completa, entonces el segundo proceso se ejecuta, da acceso al completado y espera su turno, sin embargo, el primer proceso ya se completó y nunca se ejecutaría para devolver el acceso al último. Por lo tanto, el segundo proceso espera infinitamente entonces.
Segunda versión de la solución de Dekker: para eliminar la sincronización de bloqueo, utiliza dos banderas para indicar su estado actual y las actualiza en consecuencia en la sección de entrada y salida.
 

CPP

Main()
{
 
    // flags to indicate if each thread is in
    // its critical section or not.
    boolean thread1 = false;
    boolean thread2 = false;
 
    startThreads();
}
 
Thread1()
{
 
    do {
 
        // entry section
        // wait until thread2 is in its critical section
        while (thread2 == true)
            ;
 
        // indicate thread1 entering its critical section
        thread1 = true;
 
        // critical section
 
        // exit section
        // indicate thread1 exiting its critical section
        thread1 = false;
 
        // remainder section
 
    } while (completed == false)
}
 
Thread2()
{
 
    do {
 
        // entry section
        // wait until thread1 is in its critical section
        while (thread1 == true)
            ;
 
        // indicate thread2 entering its critical section
        thread2 = true;
 
        // critical section
 
        // exit section
        // indicate thread2 exiting its critical section
        thread2 = false;
 
        // remainder section
 
    } while (completed == false)
}

Python3

def Thread1():
    doWhile=False
    while not completed or not doWhile:
        doWhile=True
        # entry section
        # wait until thread2 is in its critical section
        while (thread2):
            pass
 
        # indicate thread1 entering its critical section
        thread1 = True
 
        # critical section
 
        # exit section
        # indicate thread1 exiting its critical section
        thread1 = False
 
        # remainder section
 
def Thread2():
    doWhile=False
    while not completed or not doWhile:
        doWhile=True
        # entry section
        # wait until thread1 is in its critical section
        while (thread1):
            pass
 
        # indicate thread1 entering its critical section
        thread2 = True
 
        # critical section
 
        # exit section
        # indicate thread2 exiting its critical section
        thread2 = False
 
        # remainder section
         
if __name__ == '__main__':
 
    # flags to indicate if each thread is in
    # its critical section or not.
    thread1 = False
    thread2 = False
 
    startThreads()

El problema que surge en la versión anterior es la exclusión mutua en sí misma. Si los subprocesos se reemplazan (se detienen) durante la actualización de la bandera (es decir, durante current_thread = true), ambos subprocesos ingresan a su sección crítica una vez que se reinicia el subproceso reemplazado, también se puede observar lo mismo al inicio, cuando ambas banderas son falsas. .
Tercera versión de la solución de Dekker: para volver a garantizar la exclusión mutua, establece las banderas antes de la sección de entrada.
 

C++

Main()
{
 
    // flags to indicate if each thread is in
    // queue to enter its critical section
    boolean thread1wantstoenter = false;
    boolean thread2wantstoenter = false;
 
    startThreads();
}
 
Thread1()
{
 
    do {
 
        thread1wantstoenter = true;
 
        // entry section
        // wait until thread2 wants to enter
        // its critical section
        while (thread2wantstoenter == true)
            ;
 
        // critical section
 
        // exit section
        // indicate thread1 has completed
        // its critical section
        thread1wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}
 
Thread2()
{
 
    do {
 
        thread2wantstoenter = true;
 
        // entry section
        // wait until thread1 wants to enter
        // its critical section
        while (thread1wantstoenter == true)
            ;
 
        // critical section
 
        // exit section
        // indicate thread2 has completed
        // its critical section
        thread2wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}

Python3

if __name__=='__main__':
    # flags to indicate if each thread is in
    # queue to enter its critical section
    thread1wantstoenter = False
    thread2wantstoenter = False
 
    startThreads()
 
 
def Thread1():
    doWhile=False
    while (completed == False or not doWhile):
        doWhile=True
        thread1wantstoenter = True
 
        # entry section
        # wait until thread2 wants to enter
        # its critical section
        while (thread2wantstoenter == True):
            pass
             
 
        # critical section
 
        # exit section
        # indicate thread1 has completed
        # its critical section
        thread1wantstoenter = False
 
        # remainder section
 
 
def Thread2():
    doWhile=False
    while (completed == False or not doWhile) :
        doWhile=True
        thread2wantstoenter = True
 
        # entry section
        # wait until thread1 wants to enter
        # its critical section
        while (thread1wantstoenter == True):
            pass
             
 
        # critical section
 
        # exit section
        # indicate thread2 has completed
        # its critical section
        thread2wantstoenter = False
 
        # remainder section

El problema con esta versión es una posibilidad de punto muerto. Ambos subprocesos podrían establecer su indicador como verdadero simultáneamente y ambos esperarán infinitamente más adelante.
Cuarta versión de la solución de Dekker: utiliza un pequeño intervalo de tiempo para volver a verificar la condición, elimina el interbloqueo y también garantiza la exclusión mutua.
 

CPP

Main()
{
 
    // flags to indicate if each thread is in
    // queue to enter its critical section
    boolean thread1wantstoenter = false;
    boolean thread2wantstoenter = false;
 
    startThreads();
}
 
Thread1()
{
 
    do {
 
        thread1wantstoenter = true;
 
        while (thread2wantstoenter == true) {
 
            // gives access to other thread
            // wait for random amount of time
            thread1wantstoenter = false;
 
            thread1wantstoenter = true;
        }
 
        // entry section
        // wait until thread2 wants to enter
        // its critical section
 
        // critical section
 
        // exit section
        // indicate thread1 has completed
        // its critical section
        thread1wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}
 
Thread2()
{
 
    do {
 
        thread2wantstoenter = true;
 
        while (thread1wantstoenter == true) {
 
            // gives access to other thread
            // wait for random amount of time
            thread2wantstoenter = false;
 
            thread2wantstoenter = true;
        }
 
        // entry section
        // wait until thread1 wants to enter
        // its critical section
 
        // critical section
 
        // exit section
        // indicate thread2 has completed
        // its critical section
        thread2wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}

Python3

if __name__ == '__main__':
 
    # flags to indicate if each thread is in
    # queue to enter its critical section
    thread1wantstoenter = False
    thread2wantstoenter = False
 
    startThreads()
 
 
def Thread1():
    doWhile=False
    while (completed == False or not doWhile):
        doWhile=True
        thread1wantstoenter = True
 
        while (thread2wantstoenter == True) :
 
            # gives access to other thread
            # wait for random amount of time
            thread1wantstoenter = False
 
            thread1wantstoenter = True
         
 
        # entry section
        # wait until thread2 wants to enter
        # its critical section
 
        # critical section
 
        # exit section
        # indicate thread1 has completed
        # its critical section
        thread1wantstoenter = False
 
        # remainder section
 
     
 
 
def Thread2():
    doWhile=False
    while (completed == False or not doWhile):
        doWhile=True
        thread2wantstoenter = True
 
        while (thread1wantstoenter == True) :
 
            # gives access to other thread
            # wait for random amount of time
            thread2wantstoenter = False
 
            thread2wantstoenter = True
         
 
        # entry section
        # wait until thread1 wants to enter
        # its critical section
 
        # critical section
 
        # exit section
        # indicate thread2 has completed
        # its critical section
        thread2wantstoenter = False
 
        # remainder section

El problema de esta versión es el aplazamiento indefinido. Además, una cantidad de tiempo aleatoria es errática según la situación en la que se implemente el algoritmo, por lo que no es una solución aceptable en sistemas críticos para el negocio.
Algoritmo de Dekker: solución final y completa: la idea es usar la noción de hilo favorito para determinar la entrada a la sección crítica. El subproceso favorito alterna entre el subproceso que proporciona la exclusión mutua y evita el interbloqueo, el aplazamiento indefinido o la sincronización de bloqueo.
 

CPP

Main()
{
 
    // to denote which thread will enter next
    int favouredthread = 1;
 
    // flags to indicate if each thread is in
    // queue to enter its critical section
    boolean thread1wantstoenter = false;
    boolean thread2wantstoenter = false;
 
    startThreads();
}
 
Thread1()
{
    do {
 
        thread1wantstoenter = true;
 
        // entry section
        // wait until thread2 wants to enter
        // its critical section
        while (thread2wantstoenter == true) {
 
            // if 2nd thread is more favored
            if (favaouredthread == 2) {
 
                // gives access to other thread
                thread1wantstoenter = false;
 
                // wait until this thread is favored
                while (favouredthread == 2)
                    ;
 
                thread1wantstoenter = true;
            }
        }
 
        // critical section
 
        // favor the 2nd thread
        favouredthread = 2;
 
        // exit section
        // indicate thread1 has completed
        // its critical section
        thread1wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}
 
Thread2()
{
 
    do {
 
        thread2wantstoenter = true;
 
        // entry section
        // wait until thread1 wants to enter
        // its critical section
        while (thread1wantstoenter == true) {
 
            // if 1st thread is more favored
            if (favaouredthread == 1) {
 
                // gives access to other thread
                thread2wantstoenter = false;
 
                // wait until this thread is favored
                while (favouredthread == 1)
                    ;
 
                thread2wantstoenter = true;
            }
        }
 
        // critical section
 
        // favour the 1st thread
        favouredthread = 1;
 
        // exit section
        // indicate thread2 has completed
        // its critical section
        thread2wantstoenter = false;
 
        // remainder section
 
    } while (completed == false)
}

Python3

if __name__ == '__main__':
 
    # to denote which thread will enter next
    favouredthread = 1
 
    # flags to indicate if each thread is in
    # queue to enter its critical section
    thread1wantstoenter = False
    thread2wantstoenter = False
 
    startThreads()
 
 
def Thread1():
    doWhile=False
    while (completed == False or not doWhile) :
        doWhile=True
        thread1wantstoenter = True
 
        # entry section
        # wait until thread2 wants to enter
        # its critical section
        while (thread2wantstoenter == True) :
 
            # if 2nd thread is more favored
            if (favaouredthread == 2) :
 
                # gives access to other thread
                thread1wantstoenter = False
 
                # wait until this thread is favored
                while (favouredthread == 2):
                    pass
                     
 
                thread1wantstoenter = True
             
         
 
        # critical section
 
        # favor the 2nd thread
        favouredthread = 2
 
        # exit section
        # indicate thread1 has completed
        # its critical section
        thread1wantstoenter = False
 
        # remainder section
 
      
 
 
def Thread2():
    doWhile=False
    while (completed == False or not doWhile) :
        doWhile=True
        thread2wantstoenter = True
 
        # entry section
        # wait until thread1 wants to enter
        # its critical section
        while (thread1wantstoenter == True) :
 
            # if 1st thread is more favored
            if (favaouredthread == 1) :
 
                # gives access to other thread
                thread2wantstoenter = False
 
                # wait until this thread is favored
                while (favouredthread == 1):
                    pass
                     
 
                thread2wantstoenter = True
             
         
 
        # critical section
 
        # favour the 1st thread
        favouredthread = 1
 
        # exit section
        # indicate thread2 has completed
        # its critical section
        thread2wantstoenter = False
 
        # remainder section
 
     

Esta versión garantiza una solución completa al problema de solución crítica.
Referencias – Algoritmo de Dekker  
-csisdmz.ul.ie Algoritmo de  
Dekker – Wikipedia
 

Publicación traducida automáticamente

Artículo escrito por Sudarshan Khasnis y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *