Modelo de computación paralela

1. Introducción. Corutinismo competitivo


Los artículos anteriores sobre el tema de la programación automática eran solo "flores". La "baya" de la programación automática, es decir para lo que necesita hacer, es un modelo de computación paralela basado en el modelo de máquina de estados. Entonces, vamos ...

El estándar C ++ incluía el soporte largamente esperado para multihilo [1]. Pero no lo admiraremos ni criticaremos este hecho, porque El trabajo con subprocesos se ve afectado por tantas condiciones, advertencias y características que, sin ejemplos reales que revelen problemas de subprocesos múltiples, una discusión sobre la programación de subprocesos múltiples no solo será apresurada, sino también bastante sesgada. Por lo tanto, en lo sucesivo no se trata principalmente de flujos, sino de autómatas, teniendo en cuenta, por supuesto, los primeros.

El lenguaje C ++ está lejos de ser el primero, complementado por construcciones de paralelismo. En los años 60 del siglo pasado, N. Wirth propuso una extensión paralela del lenguaje ALGOL [2]. Sin embargo, los próximos 60 años no han aclarado qué debería considerarse un algoritmo paralelo y cuál debería ser el modelo de computación paralela. Aparentemente, esta extensión tardía del lenguaje C ++ también está relacionada con esto.

Tanto las construcciones de larga data del lenguaje ALGOL, como sus análogos más modernos en el lenguaje C ++, son solo métodos de paralelización estructural que no introducen un modelo algorítmico paralelo. Para justificar esto, se puede decir que los intentos realizados en el pasado para crear un modelo de cálculos tan formal han fallado. Baste decir que las mismas redes de Petri no justificaron las grandes esperanzas depositadas en ellos.

Como resultado, la "espiral" del desarrollo del paralelismo parece haber regresado a su origen, habiendo experimentado solo un "desarrollo terminológico". Las corutinas triviales anteriores se convirtieron repentinamente en "corutinas" avanzadas (papel de seguimiento de la corutina inglesa), y la confusión con los conceptos de paralelo y concurrente en el segmento de programación paralela en inglés a veces conduce a cosas paradójicas. Por ejemplo, la primera edición del libro [1] difiere de la segunda edición al reemplazar los términos "paralelo" con "competitivo" y "multiproceso" con "paralelo". Así que descubra esto en la situación de "quién es quién".

2. Modelo de cálculos de autómatas paralelos


Probablemente, nadie discutirá que el siguiente paso cualitativo en el desarrollo de la programación está relacionado con la transición a un modelo de computación paralela. Pero si esto sucederá como resultado del desarrollo evolutivo del modelo computacional existente o si será un modelo fundamentalmente diferente es el tema aún en discusión. Y si los teóricos siguen discutiendo, la parte prácticamente motivada de los programadores ya está utilizando métodos estructurales para paralelizar programas.

La separación de funciones y el aumento de la productividad se consideran las únicas razones para utilizar la concurrencia. Al menos, para ellos o sus combinaciones, en última instancia, reducen o intentan reducir todos los demás [1]. Pero hay una razón de la que rara vez se habla, pero por la cual generalmente vale la pena participar en programación paralela. De hecho, la velocidad puede aumentarse por métodos puramente de hardware, y la separación de tareas con paralelismo está conectada de la misma manera que el trabajo diario de los empleados del banco con una lista de sus tareas oficiales. Y solo los algoritmos paralelos son una estrategia que nos permite vencer la complejidad de las tareas y aumentar la confiabilidad de los programas. Y todo esto contrario a la opinión predominante con respecto a la programación multiproceso, que convierte cualquier programa paralelo en un producto de software complejo y poco confiable.

Un sistema paralelo, que consta de muchos componentes, objetos, agentes, etc. que interactúan de manera paralela e interactiva, implementa un algoritmo que está determinado de muchas maneras no por los algoritmos de los componentes individuales (aunque ellos, por supuesto), sino por el número de componentes, el número y tipo de conexiones entre ellos. Para controlar esta complejidad y comprender el algoritmo del sistema paralelo, no solo necesita un modelo de computación paralela, sino un modelo que tenga, entre otras cosas, e incluso, sobre todo, una teoría apropiada.

La tesis de que "a menudo un programa paralelo es más difícil de entender ... y, por lo tanto, el número de errores está aumentando", por decirlo suavemente, es discutible. Sí, el algoritmo del programa paralelo puede ser bastante difícil de entender, pero si hay una teoría, se puede "calcular" formalmente utilizando algoritmos de componentes. Y desde el punto de vista del diseño, la implementación y el mantenimiento de los algoritmos de componentes son mucho más simples que el algoritmo del sistema en su conjunto. Al diseñar componentes más simples, obviamente cometeremos menos errores que diseñar un sistema en una sola pieza. Además, los componentes depurados pueden ser parte de otros sistemas, reduciendo la complejidad, aumentando la confiabilidad y minimizando sus costos de diseño.

3. concurrencia en serie


El artículo [3] describió el paralelismo de un modelo separado de una máquina de estados finitos. Sus canales a nivel de ejecución de transiciones especifican la ejecución paralela de las funciones / métodos asociados con ella: predicados y acciones. Al mismo tiempo, no hay restricciones en el paralelismo predicado. Cuando trabajan, no entran en conflicto entre sí, porque no afecta el contenido de la memoria. Las acciones, trabajando en paralelo, pueden tener datos de entrada y salida comunes, así como cambiarlos independientemente uno del otro. Y todo esto puede ser una fuente de incertidumbre en el valor de los datos de salida.

El correcto funcionamiento de las acciones en las situaciones descritas anteriormente proporciona memoria en la sombra. Al almacenar nuevos valores en él, uno puede usar los mismos datos dentro de una sola acción, tanto como entrada como salida. Un ejemplo es el modelo de un generador de pulso rectangular, descrito como y =! Y, donde y es la salida del generador. Su código C ++ en el entorno VKPa se muestra en el Listado 1, y los resultados del programa se muestran en la Fig. 1)

Listado 1. Generador de pulso rectangular
#include "lfsaappl.h"

class FSWGenerator :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FSWGenerator(pTAppCore, nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();
    FSWGenerator(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL);
    virtual ~FSWGenerator(void) {};
    CVar *pVarY;				//  
protected:
    void y1();
};

#include "stdafx.h"
#include "FSWGenerator.h"
// state machine transition table
static LArc TBL_SWGenerator[] = {
    LArc("s1",		"s1","--",	"y1"),			//
    LArc()
};

FSWGenerator::FSWGenerator(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL):
    LFsaAppl(TBL_SWGenerator, strNam, nullptr, pCVFL)
{
    pTAppCore = pInfo;
}
// creating local variables and initialization of pointers
bool FSWGenerator::FCreationOfLinksForVariables() {
// creating local variables
    pVarY = CreateLocVar("y", CLocVar::vtBool, " ");
    return true;
}
// setting output signals
void FSWGenerator::y1() {
    pVarY->SetDataSrc(nullptr, !bool(pVarY->GetDataSrc()));
}


imagen
Higo. 1. Simulación del funcionamiento del generador de pulso rectangular en el VKPA La

máquina automática en este caso tiene una condición con una transición incondicional (una transición con un guión en el lugar de la condición de entrada) en forma de un bucle marcado por la acción y1, que implementa la inversión de la variable de salida, que forma un pulso rectangular en dinámica. Dentro del marco del modelo de autómata, la frecuencia de la señal de pulso se puede controlar configurando el valor táctil del tiempo discreto del espacio del autómata en el que se carga el autómata.

1. , . . . .


La capacidad de controlar el tiempo discreto del autómata y la presencia de muchos espacios de autómatas no son las únicas, sino importantes, propiedades distintivas del entorno VKPa. Utilizándolos, puede optimizar el rendimiento de un programa paralelo. Por ejemplo, las máquinas que implementan visualización de datos y diálogos de usuario deben ubicarse en espacios lentos de autómatas, y los procesos de aplicación deben distribuirse entre los espacios de autómatas de acuerdo con las prioridades y la velocidad deseada, etc. etc.

Dentro del marco de un modelo de autómata, el valor de la salida del generador se relaciona fácilmente con el estado actual del modelo. El código para el modelo de generador, que ya tiene dos estados, cada uno de los cuales refleja el estado de la salida del generador, se muestra en el Listado 2.

Listado 2. Generador de onda cuadrada en estados
#include "lfsaappl.h"

extern LArc TBL_SWGenState[];
class FSWGenState :
    public LFsaAppl
{
public:
    FSWGenState(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL):
    LFsaAppl(TBL_SWGenState, strNam, nullptr, pCVFL) {};
};

#include "stdafx.h"
#include "FSWGenState.h"
// state machine transition table
LArc TBL_SWGenState[] = {
    LArc("s0",		"s1","--",	"--"),			//
    LArc("s1",		"s0","--",	"--"),			//
    LArc()
};


En el nuevo modelo, los estados reemplazan la variable de salida, y esto, como se puede ver, simplificó drásticamente el modelo generador. Como resultado, obtuvimos una máquina "desnuda", representada solo por una tabla de conversión. Para monitorear su estado actual "s1" en VKPa, se creó una variable del tipo fsa (estado) con el nombre SWGenState. (S1) para un autómata llamado SWGenState. Toma un valor verdadero en el estado s1 y falso cuando la máquina está en un estado diferente. Además, esta variable ya se utiliza mediante la visualización de los datos del entorno VKPA (consulte la tendencia de la señal en la Fig. 2).

imagen
Higo. 2. Modelando el generador de estado

4. Modelo de control de computación paralela


Además, avanzando hacia la creación de un modelo de procesos paralelos, es lógico utilizar muchas máquinas de estado finito que funcionan e interactúan simultáneamente, es decir. red de autómatas. En este caso, aparece el problema de elegir un modelo de tiempo de red, que puede ser el mismo para todas las máquinas o, en el límite, individual para cada una. En VKPa, la elección se hizo a favor de una sola vez (para más detalles sobre redes síncronas de autómatas, ver [5]).

La elección de una sola vez le permite crear un álgebra de autómatas con operaciones de composición y descomposición de autómatas. Usando el primero, puede encontrar el autómata resultante, que da una idea precisa del funcionamiento de un sistema paralelo. Y aquí vale la pena recordar la tesis anterior sobre la "complejidad de la comprensión" de los programas paralelos. La presencia de la operación de composición nos permite resolver el "problema de comprensión" del programa paralelo.

Por supuesto, el autómata resultante para una red de una gran cantidad de componentes puede ser muy voluminoso. Pero, afortunadamente, a menudo se requiere una comprensión del funcionamiento de subsistemas o redes de un pequeño número de componentes, para lo cual encontrar el autómata resultante no causa grandes problemas. El siguiente ejemplo de modelo de flip-flop RS lo demuestra.

El modelo de disparo RS es un ejemplo de un sistema paralelo simple. Es especialmente interesante en presencia de retroalimentaciones cruzadas. Retroalimentaciones o, de otra manera, cadenas cíclicas, bucles, bucles algebraicos, etc. Actualmente son un problema grave para los modelos estructurales de sistemas paralelos. En el caso general, se permite mediante la introducción en los lazos de separación de elementos de memoria. Esta es la solución estándar propuesta por la teoría de los autómatas [4]. Se recomienda el mismo resultado en la persona de MATLAB. El entorno VKPa es diferente en el sentido de que no requiere la introducción de tales elementos adicionales para la implementación de bucles. Tenga en cuenta, y esto es muy importante, los circuitos reales tampoco los necesitan (vea el circuito RS-flip-flop).

En la Fig. La Figura 3 presenta el modelo más simple del elemento AND-NOT, en el que consiste el circuito de disparo RS. No tiene en cuenta los retrasos de los elementos, así como su tipo (retrasos de transporte o inerciales). Sin embargo, todavía contiene al menos un tiempo de retraso. Este es el momento de la transición de un estado a otro. El Listado 3 muestra el código del modelo

imagen
. 3. El modelo del elemento Y NO

Listado 3. Modelo de elemento Y NO
#include "lfsaappl.h"

class FIne :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FIne(pTAppCore, nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();
    FIne(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL);
    virtual ~FIne(void) {};
    CVar *pVarX1;				//  
    CVar *pVarX2;				//  
    CVar *pVarY;				//  
    CVar *pVarStrNameX1;		//    
    CVar *pVarStrNameX2;		//    
    CVar *pVarStrNameY;         //   
protected:
    int x1(); int x2(); int x12();
    void y1(); void y2(); void y12();
    bool bX1, bX2, bY;
};


#include "stdafx.h"
#include "FIne.h"
// state machine transition table
static LArc TBL_Ine[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"s1","x12^x1",	"y1"),		//
    LArc("st",		"s1","x12^x2",	"y1"),		//
    LArc("st",		"s0","x12x1x2",	"y2"),		//
    LArc("s1",		"s0","x1x2",   "y2"),		//
    LArc("s0",		"s1","^x1",    "y1"),		//
    LArc("s0",		"s1","^x2",    "y1"),		//
    LArc()
};

FIne::FIne(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL):
    LFsaAppl(TBL_Ine, strNam, nullptr, pCVFL)
{ }

// creating local variables and initialization of pointers
bool FIne::FCreationOfLinksForVariables() {
// creating local variables
    pVarX1 = CreateLocVar("x1", CLocVar::vtBool, " 1- ");
    pVarX2 = CreateLocVar("x2", CLocVar::vtBool, " 2- ");
    pVarY = CreateLocVar("y", CLocVar::vtBool, " ");
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable(x1)");			//   
    pVarStrNameX2 = CreateLocVar("strNameX2", CLocVar::vtString, "name of external input variable(x2)");			//   
    pVarStrNameY = CreateLocVar("strNameY", CLocVar::vtString, "name of external output variable(y)");		//   
// initialization of pointers
    string str;
    if (pVarStrNameX1) {
        str = pVarStrNameX1->strGetDataSrc();
        if (str != "") { pVarX1 = pTAppCore->GetAddressVar(str.c_str(), this);	}
    }
    if (pVarStrNameX2) {
        str = pVarStrNameX2->strGetDataSrc();
        if (str != "") { pVarX2 = pTAppCore->GetAddressVar(str.c_str(), this); }
    }
    if (pVarStrNameY) {
        str = pVarStrNameY->strGetDataSrc();
        if (str != ""){pVarY = pTAppCore->GetAddressVar(str.c_str(), this);}
    }
    return true;
}

int FIne::x1() { return bool(pVarX1->GetDataSrc()); }
int FIne::x2() { return bool(pVarX2->GetDataSrc()); }
int FIne::x12() { return pVarX1 != nullptr && pVarX2 && pVarY; }

void FIne::y1() { pVarY->SetDataSrc(nullptr, 1); }
void FIne::y2() { pVarY->SetDataSrc(nullptr, 0.0); }
void FIne::y12() { FInit(); }


En la Fig. 4 muestra un diagrama de un flip-flop RS y su modelo en forma de máquina de estados finitos. Las flechas en el modelo indican las conexiones entre los autómatas de la red. Aquí, por un lado, los estados de los modelos reflejan los estados de las salidas del elemento y, por otro lado, también se utilizan como señales para organizar enlaces de información entre procesos paralelos. Es esta forma del modelo (con sincronización a través de estados) lo que hace que sea bastante fácil encontrar el autómata resultante de la red. Se muestra en la fig. 5 (para el procedimiento para encontrar el autómata resultante, consulte [6] para más detalles).

Compare el algoritmo [resultante] del programa paralelo RS-flip-flop y el algoritmo de operación de un elemento AND-NOT separado. La diferencia es sorprendente. En este caso, los algoritmos de los componentes se crean mediante "manejadores", y el algoritmo del sistema paralelo se crea implícitamente, mediante la "inteligencia artificial" de la red. Esta es la diferencia cualitativa entre los programas paralelos y los secuenciales: cambiando solo las comunicaciones (al menos una), obtendremos un algoritmo de trabajo completamente diferente. Y definitivamente ya no será un disparador RS. Y, por cierto, otro autómata resultante.

imagen
Higo. 4. Esquema del RS-FF y modelo de red

imagen
Fig. 5. El modelo de red de máquina resultante RS-trigger

El análisis del autómata resultante en la Fig. 5 proporciona la siguiente "comprensión" del programa paralelo (y el desencadenante real, por supuesto). En primer lugar, cuando se cambia de un estado a otro, el activador pasará necesariamente por el estado "prohibido" de las salidas (¿y qué dicen los libros de texto sobre esto?). En segundo lugar, si el disparador se activa en un solo estado de salidas (en el estado "s1w1"), y luego se alimentan dos unidades a las entradas, entrará en el modo de generación, es decir conmutación cíclica entre los estados "s1w1" y "s0w0" y (¿y ha oído hablar de la generación de disparadores?).

También se produce una transición a través de un estado prohibido en un activador real, pero el modo de generación es imposible debido a la diferencia en los retrasos de los elementos reales. Higo. La Figura 6 muestra el modo de generación del modelo de disparador de activación, que existe siempre que las unidades en las entradas estén almacenadas.

Observación 2. Una descripción típica del funcionamiento del disparador RS se da en la abrumadora mayoría de los casos en forma de una tabla de verdad. Pero para hacerlo, entendiendo que un disparador es un esquema secuencial, de hecho, está engañando deliberadamente a quienes estudian este tema. Bueno, ¡ningún disparador puede tener "estados prohibidos"! Pero por alguna razón, solo unos pocos deciden descubrir esta verdad y, especialmente, discutir el problema de su generación (ver, por ejemplo, [7]).


Higo. 7 muestra el cambio de un modelo de disparo entre sus estados estables. Aquí, un solo estado de las entradas de activación retiene el estado actual de las salidas de activación, y cuando esta o aquella entrada se establece en cero, cambia al estado opuesto. Al mismo tiempo, cuando se activa el disparador, sus salidas en el momento igual a una medida discreta toman al mismo tiempo un solo estado (¿prohibido por quién?).

imagen
Higo. 6. Modo de generación de disparador RS

imagen
Fig. 7. Cambio de disparador RS entre estados

Considere otro modelo de disparador RS, que consta de un estado y una acción, es decir similar al modelo en el Listado 1. Su código se muestra en el Listado 4. Este modelo, como el modelo generador, no tiene predicados y los valores de la señal sin ninguna transformación intermedia se ingresan a la acción y1. ¿Esto es bueno o malo? Por un lado, parece que es bueno, porque el código se ha vuelto más simple, pero por otro lado ... no realmente. Y entenderemos las razones de esto ahora.

Listado 4. Modelo de elemento NAND de una acción
#include "lfsaappl.h"

class FTwoOperators :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FTwoOperators(pTAppCore, nameFsa, pCVarFsaLibrary); }
    bool FCreationOfLinksForVariables();
    FTwoOperators(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL);
    virtual ~FTwoOperators(void) {};
    CVar *pVarX1;				//  
    CVar *pVarX2;				//  
    CVar *pVarY;				//  
    CVar *pVarStrNameX1;		//    
    CVar *pVarStrNameX2;		//    
    CVar *pVarStrNameY;         //   
protected:
    int x12();
    void y1(); void y12();
    bool bX1, bX2, bY;
};

#include "stdafx.h"
#include "FTwoOperators.h"
// state machine transition table
static LArc TBL_TwoOperators[] = {
    LArc("st",		"st","^x12","y12"), 		//
    LArc("st",		"s1","x12", "--"),		//
    LArc("s1",		"s1","--",  "y1"),		//
    LArc()
};

FTwoOperators::FTwoOperators(TAppCore *pInfo, string strNam, CVarFsaLibrary *pCVFL):
    LFsaAppl(TBL_TwoOperators, strNam, nullptr, pCVFL)
{ }
// creating local variables and initialization of pointers
bool FTwoOperators::FCreationOfLinksForVariables() {
// creating local variables
    pVarX1 = CreateLocVar("x1", CLocVar::vtBool, " 1- ");
    pVarX2 = CreateLocVar("x2", CLocVar::vtBool, " 2- ");
    pVarY = CreateLocVar("y", CLocVar::vtBool, " ");
    pVarStrNameX1 = CreateLocVar("strNameX1", CLocVar::vtString, "name of external input variable(x1)");			//   
    pVarStrNameX2 = CreateLocVar("strNameX2", CLocVar::vtString, "name of external input variable(x2)");			//   
    pVarStrNameY = CreateLocVar("strNameY", CLocVar::vtString, "name of external output variable(y)");		//   
// initialization of pointers
    string str;
    if (pVarStrNameX1) {
        str = pVarStrNameX1->strGetDataSrc();
        if (str != "") { pVarX1 = pTAppCore->GetAddressVar(str.c_str(), this);	}
    }
    if (pVarStrNameX2) {
        str = pVarStrNameX2->strGetDataSrc();
        if (str != "") { pVarX2 = pTAppCore->GetAddressVar(str.c_str(), this); }
    }
    if (pVarStrNameY) {
        str = pVarStrNameY->strGetDataSrc();
        if (str != "") { pVarY = pTAppCore->GetAddressVar(str.c_str(), this);	}
    }
    return true;
}

int FTwoOperators::x12() { return pVarX1 != nullptr && pVarX2 && pVarY; }

void FTwoOperators::y1() {
// reading input signals
    bX1 = bool(pVarX1->GetDataSrc());
    bX2 = bool(pVarX2->GetDataSrc());
// setting output signals
    bY = !(bX1&&bX2);
    pVarY->SetDataSrc(nullptr, bY);
}
// initialization of pointers
void FTwoOperators::y12() { FInit(); }


Si probamos el nuevo modelo en el modo de "memoria oculta", no veremos ninguna diferencia en su funcionamiento con respecto al anterior, es decir, y, cambiando, pasará por los estados prohibidos y entrará regularmente en el modo de generación. Si configuramos el trabajo con datos en el modo habitual, obtendremos los resultados que se muestran en la Fig. 8 y fig. 9.

imagen
Fig. 8. Fallo del modo de generación del modelo de disparo RS

imagen
. 9. Omitiendo estados prohibidos por el

modelo de disparo RS ¿Por qué el primer modelo, independientemente del modo de trabajar con la memoria, muestra resultados estables y el segundo cambia el comportamiento? La razón son los predicados. El segundo modelo no tiene predicados, y esto es crítico para su comportamiento. Pero, ¿cómo y por qué la presencia / ausencia de predicados afecta el algoritmo de operación del programa paralelo?

El modelo de programa de un elemento AND-NOT, como un programa de autómata, tiene dos canales de entrada y un canal de salida. Deben coincidir con dos predicados y una acción. El primer programa es totalmente consistente con esto. El kernel VKPa, que interpreta la descripción del autómata, primero ejecuta todos los predicados no solo de un autómata en particular, sino de todo el espacio del autómata, y solo entonces inicia todas las acciones. En este caso, en cualquier secuencia en que se ejecutaron las acciones, simulando paralelismo, y en cualquier modo en que trabajaran con memoria, los resultados de los predicados en el ciclo de reloj actual del autómata no dependen de ellas (acciones). Por lo tanto, el primer programa produce el mismo resultado.

El segundo programa, aunque funciona directamente con los canales de entrada de la máquina, lee las señales de entrada como parte de la acción. Las acciones, trabajando con datos de entrada en el modo de memoria oculta, escriben nuevos valores en la memoria oculta y, por lo tanto, trabajan con datos válidos al comienzo de un ciclo de reloj discreto. En el modo habitual, "agarran" los valores instantáneos establecidos en el momento de su cambio, y por lo tanto el algoritmo se vuelve dependiente de los momentos de cambio de memoria. El segundo programa demuestra una dependencia similar. E incluso si se introdujeran métodos predicados en el segundo modelo, esto no tendría ningún efecto en los resultados de su trabajo. Lo que importa aquí no es el hecho de la existencia de métodos predicados, sino las características de su trabajo en el marco del modelo de programación de autómatas.

5. Conclusiones


Usando el programa paralelo RS-trigger como ejemplo, examinamos algunas de las propiedades inherentes a cualquier programa paralelo. Continuaremos considerando ciertos aspectos generales del funcionamiento de programas paralelos como un ejemplo de circuitos lógicos (digitales). La elección del tema de modelado de circuitos digitales aquí no es accidental. De hecho, en "forma refinada" representan el trabajo de procesos paralelos. Esto hace el análisis de los matices de concurrencia, raza, sincronización, callejones sin salida, etc. etc. Transparente, claro y simple.

Al mismo tiempo, no importa cómo llame a la programación: "competitiva" o paralela, ya sea que use "corutinas", corutinas, hilos o máquinas para la programación, el resultado del programa [paralelo] debe ser el mismo en todas las implementaciones. El modelo automático de programas paralelos en el marco del PCUS persigue este y solo este objetivo.
Cualesquiera que sean las suposiciones sobre la implementación del núcleo de la interpretación de los autómatas del entorno del VKPa, todas estas serían "especulaciones", porque El resultado del trabajo de los programas automáticos no debe asociarse con la implementación de un modelo computacional. Puede ser software (como lo es ahora) o hardware (como espero en el futuro), implementado en un núcleo o en su conjunto, en versión de subproceso único o multiproceso, etc. etc. todo esto de ninguna manera debería afectar los resultados de los programas automáticos paralelos.

Y, al parecer, se logró el objetivo. El modelo RS-trigger, como una de las posibles pruebas de paralelismo del sistema [8], convence de esto ... Como lo ha demostrado la vida, todos los demás programas paralelos, siempre que el entorno ejecute la prueba RS-trigger con éxito en paralelo, funcionan de la misma manera correcta, confiable y estable . Por cierto, la misma "prueba de disparo RS" de MATLAB no pasó, y esto ya dice mucho ...

Literatura
1. . ++ . . . . .. – .: , 2012. – 672 .
2. . : . . – .: , 1981. – 360 .
3. . [ ], : habr.com/ru/post/484588 . . . ( 07.01.2020).
4. .. . .: , 1962.
5. .., - .. . – 2- ., . . – .: , 1988. – 480 .
6. .. . [ ], : cloud.mail.ru/public/HwsK/T95PMM8Ed . . . ( 01.02.2020).
7. . . 2- . – .: , 2004. – 432.
8. .. ? “ ”, №10/97, .116-119. [ ], : www.osp.ru/pcworld/1997/10/158015 . . . ( 01.02.2020).

Source: https://habr.com/ru/post/undefined/


All Articles