A linguagem Concurrent Basic representa um possível futuro para o Visual Basic. Apesar de ser baseada no trabalho feito em linguagens de pesquisa derivadas do C# como o Polyphonic C# e o C-Omega, ela foi baseada no Visual Basic por sua predisposição inerente em ser utilizada para programação declarativa. Esta sintaxe é até mesmo inspirada nos VB’s event handlers declarativos do VB.
Palavras-chave
- * Asynchronous – Um método que representa uma fila de mensagens.
- * Synchronous – Um método que repersenta uma fila de requisições.
- * When – Utilizado para interligar os eventos com Asynchronous e Synchronous
Abaixo há um exemplo completo de um buffer thread-safe implementado utilizando-se estas palavras-chave:
Class Buffer(Of T) Asynchronous Sub Put (t as T) Synchronous Function Take() as T Function React (t as T) as T When Put, Take Return T End Function End Class
A função Put pode ser chamada por um consumidor assincronamente. A função Take irá bloquear a execução até que haja ao menos um Put pendente. A função React cuida dos detalhes de implementação da conversão do objeto enfileirado com Put para a forma esperada pelo Take.
Abaixo há mais dois exemplos. O primeiro espera por uma mensagem de A ou B. O segundo espera até que haja uma mensagem em A e em B.
Class Either(Of T) Asynchronous Sub PutA(t as T) Asynchronous Sub PutB(t as T) Synchronous Function TakeEither() as T Function ReactA(t as T) as T When TakeEither, PutA Return T End Function Function ReactB(t as T) as T When TakeEither, PutB Return T End Function End Class Class Both(Of T, U) Asynchronous Sub PutA(t as T) Asynchronous Sub PutB(u of U) Synchronous Function TakeBoth() as T Function React(t as T, u as U) as Pair(Of T, U) When Take, PutA, PutB Return new Pair(Of T, U)(t, u) End Function End Class
Em seguida, há um pattern para a criação de um buffer com apenas uma posição, que é um buffer que armazena no máximo uma menssagem por vez.
Class OPB(of T) Sub New Empty() End Sub Synchronous Sub Put (t as T) Synchronous Function Take() as T Private Asynchronous Empty() Private Asynchronous Full(of T) Sub PutAndEmpty(t as T) When Put, Empty Full(t) End Sub Sub TakeAndFull(t as T) as T When Take, Full Empty() Return t End Sub End Class
Por trás das cortinas, o Put, Take, Empty e o Full representam filas internas. Os métodos de reação são executados através “pattern matching” entre cláusulas When e o tamanho das filas.
Até agora agora exemplo presumiu que o método Take seria síncrono. Entretanto, não precisa ser, pois ele também pode utilizar callback.
Class AsyncBuffer(Of T) Asynchronous Sub Put (t as T) Asynchronous Function Take() as T Function React (callback as Func(t as T), t as T) as T When Put, Take Return callback(t) End Function End Class
Utilizando-se este modelo, uma thread é criada para processar o React e as funções de callback. Algumas pessoaS podem querer fazer algo a mais como utilizar um pool de threads, um thread de GUI ou alguma outra biblioteca de concorrência. Para fazer isso, você precisa implementar ContinuationAttribute. Abaixo está a classe base para este atributo.
Inherits Attribute Public MustOverride Sub BeginInvoke( task As Continuation) Public MustOverride Sub Invoke( task As Continuation) End Class Public Delegate Sub Continuation()
Exemplo e uso
Public Class MyThreadPoolAttribute Inherits ContinuationAttribute Public Overrides Sub BeginInvoke( task As Continuation) ThreadPool.Enqueue(task) End Sub Public Overrides Sub Invoke( task As Continuation) task() End Sub End ClassClass AsyncBuffer(Of T)
Asynchronous Sub Put (t as T)
Asynchronous Function Take() as T
Function React (callback as Func(t as T), t as T) as T When Put, Take
Return callback(t)
End Function
End Class
Para mais informações, você pode assistir o vídeo do Channel 9 e ver a proposta Concurrent Basic.