
Prefácio
Deixe-me lembrá-lo de que esse idioma foi desenvolvido por mim para fins educacionais como parte de um hobby. Não o considero (no momento) uma linguagem idealmente desenvolvida, mas quem sabe o que o futuro pode esperar.
Se você deseja experimentá-lo em ação - faça o download
do repositório do projeto, nele você pode encontrar a versão montada do projeto ou montá-lo você mesmo, para o seu sistema operacional.
1. Introdução
Multithreading e assincronismo em nossos dias são um dos componentes mais importantes das linguagens de programação modernas.
Portanto, decidi adicionar suporte a projetos e tecnologias modernas à minha linguagem de programação, em parte adicionando projetos simples e convenientes à linguagem.
Fluxos rápidos
Eles facilitam o paralelismo da execução do código.
Para isso, o lançamento: ... construção final foi adicionada ao Mash
Exemplo 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
Exemplo de saída:
9 1 2 7 5 3 10 4 6 8
Quando a execução do programa atinge launch..end, o código dentro desse bloco é iniciado em um thread separado, e a execução do código de inicialização é transferida para esse bloco.
Você pode encontrar quase a mesma construção de linguagem anteriormente na linguagem de programação Kotlin.
Assinatura e espera
A implementação de corotinas por si só não é suficiente para mim, é por isso que as construções assíncronas e de espera também são adicionadas ao Mash.
O Async permite converter a execução do código em um thread separado e continuar a execução do código principal.
A espera permite aguardar o momento em que todos os blocos assíncronos necessários forem concluídos.
Exemplo 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
Conclusão:
Hello! Test Test 2 Test 2 Test 2 Test Test End!
Multithreading clássico
A principal base de código que fornece suporte para multithreading está concentrada no módulo? <threads>.
Os principais componentes que serão discutidos posteriormente:
1) Classe TThread (apenas uma declaração de classe é fornecida, o código completo fica mais adiante no 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) classe TCriticalSection (sua descrição):
class TCriticalSection: protected: var Critical_Section_Controller public: proc Create, Free //Methods proc Enter, Leave func TryEnter end
3) Métodos para criar e iniciar threads rapidamente:
func Async(method, ...) func Thread(method, ...) func Parallel(method, ...)
4) Atômico seguro para thread (classe variável para interação entre threads):
class TAtomic: private: var Locker, Value public: proc Create, Free proc Set func Get end
5) Corotinas:
class TCoroutine(TThread): public: var NextCoroutine proc Create proc Yield, YieldFor end
Então, vamos colocar em ordem.
A classe TThread nos permite criar uma nova classe sucessora com base nela, adicionando as variáveis necessárias aos seus campos, que serão transferidas para o novo thread.
Código de exemplo imediato:
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
Se estivermos com preguiça de descrever uma nova classe para criar um fluxo, podemos recuperar o suporte para a redefinição dinâmica de métodos em instâncias de classe e usá-lo.
Exemplo 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
Se precisarmos apenas executar o método com os parâmetros em um novo thread, os métodos async (), thread () e parallel () são exatamente o que precisamos.
Um exemplo de como iniciar um método em um novo 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
Como você deve ter notado anteriormente, esses três métodos são funções e retornam - classes semelhantes ao TThread.
A diferença deles é que async () cria um encadeamento que, após a conclusão, libera memória de si mesmo, e uma instância da classe TThread é excluída automaticamente,
thread () é o mesmo que assíncrono (), somente o thread é criado inicialmente congelado.
E finalmente paralelo () - cria um encadeamento em execução, que após a conclusão não executará autodestruição, ou seja, podemos usar qualquer método da classe TThread, por exemplo, WaitFor () e não ter medo de erros de tempo de execução. A única ressalva - você precisará ligar para Free () manualmente.
Sincronização de threads
Para fazer isso, adicionei a classe TCriticalSection ao Mash.
Exemplo 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
Atomic
Implemente um contêiner seguro para threads para armazenar quaisquer valores.
Exemplo 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
Coroutines
Essa funcionalidade permite sincronizar a execução paralela do código.
Exemplo de código:
uses <bf> uses <crt> uses <threads> proc class::Proc1(): while true: println("Hello world
Conclusão:
Hello world
Conclusão
Espero que você ache este artigo interessante.
À espera de comentários :)
PS: De acordo com seus comentários, eu removi o construto till..end do idioma. Agora seu lugar é ocupado pela construção:
whilst <>: ... end
É um loop while regular, com a diferença de que a condição é verificada após a iteração.