
Vorwort
Ich möchte Sie daran erinnern, dass diese Sprache von mir zu Bildungszwecken im Rahmen eines Hobbys entwickelt wurde. Ich halte es (im Moment) nicht für eine ideal entwickelte Sprache, aber wer weiß, was die Zukunft erwarten kann.
Wenn Sie es selbst in Aktion ausprobieren möchten, laden Sie
das Projekt-
Repository herunter. Dort finden Sie die zusammengestellte Version des Projekts oder können sie selbst für Ihr Betriebssystem zusammenstellen.
Einführung
Multithreading und Asynchronismus sind in unserer Zeit eine der wichtigsten Komponenten moderner Programmiersprachen.
Aus diesem Grund habe ich beschlossen, meiner Programmiersprache Unterstützung für moderne Designs und Technologien hinzuzufügen, indem ich der Sprache teilweise einfache und bequeme Designs hinzufügte.
Schnelle Flüsse
Sie erleichtern die Parallelisierung der Codeausführung.
Zu diesem Zweck wurde der Start: ... Endkonstruktion zu Mash hinzugefügt
Codebeispiel:
uses <bf> uses <crt> proc main(): for(i ?= 1; i <= 10; i++): launch: sleep(random() * 100) println(i) end end inputln() end
Ausgabebeispiel:
9 1 2 7 5 3 10 4 6 8
Wenn die Ausführung des Programms den Start erreicht hat, wird der Code in diesem Block in einem separaten Thread gestartet und die Ausführung des Startcodes in diesen Block übertragen.
Sie könnten fast das gleiche Sprachkonstrukt früher in der Programmiersprache Kotlin treffen.
Async & warte
Die Implementierung von Coroutinen allein reicht mir nicht aus, deshalb werden Mash auch Async & Wait-Konstrukte hinzugefügt.
Mit Async können Sie die Codeausführung in einen separaten Thread übersetzen und die Ausführung des Hauptcodes fortsetzen.
Mit Warten können Sie auf den Moment warten, in dem alle erforderlichen asynchronen Blöcke abgeschlossen sind.
Codebeispiel:
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
Fazit:
Hello! Test Test 2 Test 2 Test 2 Test Test End!
Klassisches Multithreading
Die Hauptcodebasis, die Multithreading unterstützt, konzentriert sich auf das Modul? <Threads>.
Die Hauptkomponenten, die später besprochen werden:
1) TThread-Klasse (es wird nur eine Klassendeklaration angegeben, der vollständige Code befindet sich weiter im Modul):
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) TCriticalSection-Klasse (ihre Beschreibung):
class TCriticalSection: protected: var Critical_Section_Controller public: proc Create, Free //Methods proc Enter, Leave func TryEnter end
3) Methoden zum schnellen Erstellen und Starten von Threads:
func Async(method, ...) func Thread(method, ...) func Parallel(method, ...)
4) Thread-sicheres Atom (variable Klasse für Cross-Thread-Interaktion):
class TAtomic: private: var Locker, Value public: proc Create, Free proc Set func Get end
5) Coroutinen:
class TCoroutine(TThread): public: var NextCoroutine proc Create proc Yield, YieldFor end
Nehmen wir es also in Ordnung.
Mit der TThread-Klasse können wir darauf basierend eine neue Nachfolgerklasse erstellen und die erforderlichen Variablen zu ihren Feldern hinzufügen, die in den neuen Thread übertragen werden.
Beispielcode sofort:
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
Wenn wir zu faul sind, eine neue Klasse zu beschreiben, um einen Stream zu erstellen, können wir die Unterstützung für die dynamische Neudefinition von Methoden in Klasseninstanzen zurückrufen und verwenden.
Codebeispiel:
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
Wenn wir die Methode nur mit den Parametern in einem neuen Thread ausführen müssen, sind die Methoden async (), thread () und parallel () genau das, was wir brauchen.
Ein Beispiel für das Starten einer Methode in einem neuen 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
Wie Sie vielleicht schon früher bemerkt haben, sind diese drei Methoden Funktionen und geben Klassen zurück, die TThread ähnlich sind.
Ihr Unterschied besteht darin, dass async () einen Thread erstellt, der nach Abschluss den Speicher von sich selbst freigibt und eine Instanz der TThread-Klasse automatisch gelöscht wird.
thread () ist dasselbe wie async (), nur der Thread wird anfänglich eingefroren erstellt.
Und schließlich parallel () - erstellt einen laufenden Thread, der nach Abschluss keine Selbstzerstörung durchführt, d. H. Wir können alle Methoden der TThread-Klasse verwenden, zum Beispiel WaitFor (), und haben keine Angst vor Laufzeitfehlern. Die einzige Einschränkung - Sie müssen Free () manuell aufrufen.
Thread-Synchronisation
Zu diesem Zweck habe ich Mash die TCriticalSection-Klasse hinzugefügt.
Codebeispiel:
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
Atomic
Implementieren Sie einen thread-sicheren Container zum Speichern von Werten.
Codebeispiel:
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
Coroutinen
Mit dieser Funktion können Sie die parallele Ausführung von Code synchronisieren.
Codebeispiel:
uses <bf> uses <crt> uses <threads> proc class::Proc1(): while true: println("Hello world
Fazit:
Hello world
Fazit
Ich hoffe, Sie finden diesen Artikel interessant.
Warten auf Kommentare :)
PS: Ihren Kommentaren zufolge habe ich das Konstrukt till..end aus der Sprache entfernt. Jetzt nimmt der Bau seinen Platz ein:
whilst <>: ... end
Es ist eine reguläre while-Schleife, mit dem Unterschied, dass die Bedingung nach der Iteration überprüft wird.