
Préface
Permettez-moi de vous rappeler que cette langue a été développée par moi à des fins éducatives dans le cadre d'un hobby. Je ne le considère pas (pour le moment) comme un langage idéalement développé, mais qui sait ce que l'avenir peut attendre.
Si vous souhaitez l'essayer vous-même en action - téléchargez
le référentiel du projet, vous y trouverez la version assemblée du projet ou l'assemblez vous-même, pour votre système d'exploitation.
Présentation
Le multithreading et l'asynchronisme à notre époque sont l'un des composants les plus importants des langages de programmation modernes.
Par conséquent, j'ai décidé d'ajouter la prise en charge des conceptions et technologies modernes à mon langage de programmation, en partie en ajoutant des conceptions simples et pratiques au langage.
Flux rapides
Ils facilitent la parallélisation de l'exécution du code.
Pour cela, le lancement: ... end construction a été ajouté à Mash
Exemple de code:
uses <bf> uses <crt> proc main(): for(i ?= 1; i <= 10; i++): launch: sleep(random() * 100) println(i) end end inputln() end
Exemple de sortie:
9 1 2 7 5 3 10 4 6 8
Lorsque l'exécution du programme atteint launch..end, le code à l'intérieur de ce bloc est lancé dans un thread séparé et l'exécution du code de lancement est transférée vers ce bloc.
Vous pourriez rencontrer presque la même construction de langage plus tôt dans le langage de programmation Kotlin.
Async et attendre
L'implémentation de coroutines seule ne me suffit pas, c'est pourquoi les constructions asynchrones et d'attente sont également ajoutées à Mash.
Async vous permet de traduire l'exécution de code dans un thread séparé et de continuer l'exécution du code principal.
Attendre vous permet d'attendre le moment où tous les blocs asynchrones nécessaires sont terminés.
Exemple de code:
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
Conclusion:
Hello! Test Test 2 Test 2 Test 2 Test Test End!
Multithreading classique
La base de code principale qui prend en charge le multithreading est concentrée dans le module? <threads>.
Les principaux composants qui seront abordés plus loin:
1) Classe TThread (seule une déclaration de classe est donnée, le code complet se trouve plus loin dans le module):
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) Classe TCriticalSection (sa description):
class TCriticalSection: protected: var Critical_Section_Controller public: proc Create, Free //Methods proc Enter, Leave func TryEnter end
3) Méthodes pour créer et démarrer rapidement des threads:
func Async(method, ...) func Thread(method, ...) func Parallel(method, ...)
4) Atomique thread-safe (classe variable pour l'interaction cross-thread):
class TAtomic: private: var Locker, Value public: proc Create, Free proc Set func Get end
5) Coroutines:
class TCoroutine(TThread): public: var NextCoroutine proc Create proc Yield, YieldFor end
Alors, prenons-le dans l'ordre.
La classe TThread nous permet de créer une nouvelle classe successeur basée sur elle, en ajoutant les variables nécessaires à ses champs, qui seront transférées vers le nouveau thread.
Exemple de code immédiat:
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 nous sommes trop paresseux pour décrire une nouvelle classe pour créer un flux, alors nous pouvons rappeler la prise en charge de la redéfinition dynamique des méthodes dans les instances de classe et l'utiliser.
Exemple de code:
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 nous avons juste besoin d'exécuter la méthode avec les paramètres dans un nouveau thread, alors les méthodes async (), thread () et parallel () sont exactement ce dont nous avons besoin.
Un exemple de démarrage d'une méthode dans un nouveau thread:
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
Comme vous l'avez peut-être remarqué plus tôt, ces 3 méthodes sont des fonctions et elles renvoient - des classes similaires à TThread.
Leur différence est que async () crée un thread qui, une fois terminé, libère la mémoire de lui-même, et une instance de la classe TThread est automatiquement supprimée,
thread () est identique à async (), seul le thread est créé initialement gelé.
Et enfin parallel () - crée un thread en cours d'exécution qui, une fois terminé, n'effectuera pas d'auto-destruction, c'est-à-dire nous pouvons utiliser toutes les méthodes de la classe TThread, par exemple WaitFor () et ne pas avoir peur des erreurs d'exécution. La seule mise en garde - vous devrez appeler Free () manuellement.
Synchronisation des threads
Pour ce faire, j'ai ajouté la classe TCriticalSection à Mash.
Exemple de code:
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
Atomique
Implémentez un conteneur thread-safe pour stocker toutes les valeurs.
Exemple de code:
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
Coroutines
Cette fonctionnalité vous permet de synchroniser l'exécution parallèle de code.
Exemple de code:
uses <bf> uses <crt> uses <threads> proc class::Proc1(): while true: println("Hello world
Conclusion:
Hello world
Conclusion
J'espère que cet article vous intéresse.
En attente de commentaires :)
PS: Selon vos commentaires, j'ai supprimé la construction until..end de la langue. Maintenant, sa place est prise par la construction:
whilst <>: ... end
Il s'agit d'une boucle while régulière, à la différence près que la condition est vérifiée après l'itération.