
Prólogo
Permíteme recordarte que este lenguaje fue desarrollado por mí con fines educativos como parte de un pasatiempo. No lo considero (por el momento) un lenguaje perfectamente desarrollado, pero quién sabe qué puede esperar el futuro.
Si desea probarlo usted mismo en acción, descargue
el repositorio del proyecto, en él puede encontrar la versión ensamblada del proyecto o ensamblarlo usted mismo, para su sistema operativo.
Introduccion
El subprocesamiento múltiple y el asincronismo en nuestro tiempo son uno de los componentes más importantes de los lenguajes de programación modernos.
Por lo tanto, decidí agregar soporte para diseños y tecnologías modernas a mi lenguaje de programación, en parte agregando diseños simples y convenientes al lenguaje.
Flujos rápidos
Facilitan la paralelización de la ejecución de código.
Para esto, el lanzamiento: ... la construcción final se ha agregado a Mash
Ejemplo de código:
uses <bf> uses <crt> proc main(): for(i ?= 1; i <= 10; i++): launch: sleep(random() * 100) println(i) end end inputln() end
Ejemplo de salida:
9 1 2 7 5 3 10 4 6 8
Cuando la ejecución del programa llega al inicio ... final, el código dentro de este bloque se inicia en un hilo separado, y la ejecución del código de inicio se transfiere a este bloque.
Podrías encontrar casi la misma construcción de lenguaje anteriormente en el lenguaje de programación Kotlin.
Asíncrono y espera
La implementación de corutinas por sí sola no es suficiente para mí, es por eso que las construcciones asíncronas y de espera también se agregan a Mash.
Async le permite traducir la ejecución del código en un hilo separado y continuar la ejecución del código principal.
Esperar le permite esperar el momento en que se completen todos los bloques asíncronos necesarios.
Ejemplo de código:
uses <bf> uses <crt> proc main(): println("Hello!") async a: println("Test") sleep(1000) println("Test") sleep(1000) println("Test") sleep(1000) end async b: println("Test 2") sleep(300) println("Test 2") sleep(300) println("Test 2") sleep(300) end wait a, b println("End!") inputln() end
Conclusión
Hello! Test Test 2 Test 2 Test 2 Test Test End!
Multihilo clásico
La base del código principal que proporciona soporte para subprocesos múltiples se concentra en el módulo? <threads>.
Los componentes principales que se discutirán más adelante:
1) Clase TThread (solo se proporciona una declaración de clase, el código completo se encuentra más adelante en el módulo):
class TThread: protected: var ThreadContext public: var Resumed, Terminated, FreeOnTerminate proc Create, Free proc Execute //for overriding proc Suspend, Resume, Terminate, WaitFor, ReJoin //Control proc's end
2) Clase TCriticalSection (su descripción):
class TCriticalSection: protected: var Critical_Section_Controller public: proc Create, Free //Methods proc Enter, Leave func TryEnter end
3) Métodos para crear y comenzar subprocesos rápidamente:
func Async(method, ...) func Thread(method, ...) func Parallel(method, ...)
4) Atómico seguro para subprocesos (clase variable para interacción entre subprocesos):
class TAtomic: private: var Locker, Value public: proc Create, Free proc Set func Get end
5) Corutinas:
class TCoroutine(TThread): public: var NextCoroutine proc Create proc Yield, YieldFor end
Entonces, tomémoslo en orden.
La clase TThread nos permite crear una nueva clase sucesora basada en ella, agregando las variables necesarias a sus campos, que se transferirán al nuevo hilo.
Código de muestra inmediato:
uses <bf> uses <crt> uses <threads> class MyThreadClass(TThread): var Param proc Create, Execute end proc MyThreadClass::Create(Param): $Param ?= Param TThread::Create$(true) end proc MyThreadClass::Execute(): for(i ?= 0; i < 10; i++): PrintLn(i, ": ", $Param) end end proc main(): new MyThreadClass("Thread #2!") InputLn() end
Si somos demasiado vagos para describir una nueva clase para crear una secuencia, entonces podemos recordar el soporte para la redefinición dinámica de métodos en instancias de clase y usarlo.
Ejemplo de código:
uses <bf> uses <crt> uses <threads> proc class::MyThreadedProc(): for(i ?= 0; i < 10; i++): PrintLn(i, ": Threaded hello!") end end proc main(): Thr ?= new TThread(false) Thr->Execute ?= class::MyThreadedProc Thr->Resume() InputLn() end
Si solo necesitamos ejecutar el método con los parámetros en un nuevo hilo, entonces los métodos asíncrono (), hilo () y paralelo () son exactamente lo que necesitamos.
Un ejemplo de inicio de un método en un nuevo hilo:
uses <bf> uses <crt> uses <threads> proc ThreadedProc(Arg): for(i ?= 0; i < 10; i++): PrintLn(i, ": ", Arg) end end proc main(): Async(ThreadedProc, "Thread #1!") InputLn() end
Como habrás notado anteriormente, estos 3 métodos son funciones y regresan, clases similares a TThread.
Su diferencia es que async () crea un subproceso que, al finalizar, libera memoria de sí mismo, y una instancia de la clase TThread se elimina automáticamente,
thread () es lo mismo que async (), solo el thread se crea inicialmente congelado.
Y, finalmente, paralelo (): crea un subproceso en ejecución que, una vez completado, no se autodestruirá, es decir Podemos usar cualquier método de la clase TThread, por ejemplo WaitFor () y no tener miedo a los errores de tiempo de ejecución. La única advertencia: deberá llamar a Free () manualmente.
Hilo de sincronización
Para hacer esto, agregué la clase TCriticalSection a Mash.
Ejemplo de código:
uses <bf> uses <crt> uses <threads> var CSect = new TCriticalSection() proc ThreadedProc(Arg): while true: CSect -> Enter() PrintLn(Arg) CSect -> Leave() Sleep(10) gc() end end proc CriticalThreadedProc(): while true: Sleep(3000) CSect -> Enter() Sleep(1000) PrintLn("And now...") Sleep(1000) PrintLn("Time to...") Sleep(1000) PrintLn("Critical section!") Sleep(3000) CSect -> Leave() gc() end end proc main(): Async(ThreadedProc, "I'm thread #1!!!") Async(CriticalThreadedProc) InputLn() end
Atómico
Implemente un contenedor seguro para subprocesos para almacenar cualquier valor.
Ejemplo de código:
uses <bf> uses <crt> uses <threads> proc main(): MyThreadValue ?= new TAtomic(0) launch: while true: MyThreadValue -> Set(1) Sleep(8) gc() end end launch: while true: MyThreadValue -> Set(2) Sleep(3) gc() end end launch: while true: MyThreadValue -> Set(3) Sleep(11) gc() end end while true: PrintLn(MyThreadValue -> Get()) Sleep(100) gc() end end
Corutinas
Esta funcionalidad le permite sincronizar la ejecución paralela de código.
Ejemplo de código:
uses <bf> uses <crt> uses <threads> proc class::Proc1(): while true: println("Hello world
Conclusión
Hello world
Conclusión
Espero que encuentres este artículo interesante.
Esperando comentarios :)
PD: De acuerdo con sus comentarios, eliminé la construcción hasta ... end del lenguaje. Ahora su lugar lo ocupa la construcción:
whilst <>: ... end
Es un ciclo while regular, con la diferencia de que la condición se verifica después de la iteración.