Como você implementar Erlang-como enviar e receber em C++?
Pergunta
Realmente, esta questão parece ter duas partes:
- Como implementar o padrão de correspondência?
- Como implementar enviar e receber (i.é.o modelo de agente)?
Para a correspondência de padrões parte, tenho procurado em vários projetos como Aplicação e Prop.Essas olhar muito bonito, mas não podia levá-los a trabalhar em uma versão recente (4.x) de g++.O Felix a linguagem também parece apoiar a correspondência de padrão muito bem, mas não é realmente C++.
Como para o Ator, modelo, existem implementações existentes como ATO++ e Theron, mas eu não poderia encontrar qualquer coisa, mas a de artigos sobre o antigo, e o último é single-threaded apenas [ver respostas].
Pessoalmente, eu tenho implementado atores do uso de threads e uma thread-safe fila de mensagens.As mensagens são de hash-estruturas, e usou-as em conjunto com um número de pré-processador de macros simples implementadas de correspondência de padrão.
Agora, eu posso usar o seguinte código para enviar uma mensagem:
(new Message(this))
->set("foo", "bar")
->set("baz", 123)
->send(recipient);
E o seguinte para fazer simples correspondência de padrões (qDebug
e qPrintable
são Qt-específica):
receive_and_match(m)
match_key("foo") { qDebug("foo: %s", qPrintable(m->value("foo").toString())); }
or_match_key("baz") { qDebug("baz: %d", m->value("baz").toInt()); }
or_match_ignore
end_receive
No entanto, isso parece um pouco hackish para mim, e não é muito robusta.
Como você faria isso?Fez eu perder qualquer trabalho existente?
Solução
Uma das coisas importantes sobre erlang é a forma como os recursos são usados para fazer sistemas robustos.
Enviar/receber modelo não é compartilhamento de arquivos e copiar explicitamente.Os próprios processos são leves threads.
Se você não desejo o robusto propriedades do modelo de erlang, você seria melhor usar processos reais e IPC, ao invés de threads.
Se você deseja robusto para passagem de mensagens que você pode acabar querendo serializar e deserialise o conteúdo.Especialmente com o tipo de segurança.
Correspondência de padrão em C++ não é sempre bonita, mas não vai ser um bom padrão para isso - você vai acabar criando um objeto dispatcher que usa algum tipo de polimorfismo para obter o que deseja.
Apesar de que se você não tiver cuidado pode acabar com xml sobre os tubos :)
Realmente, se você deseja que o modelo de erlang você realmente quer usar erlang.Se há lento bits, tenho certeza de que você pode aumentar o seu programa usando um estrangeiro função da internet.
O problema sobre a re-execução partes, é você não ter uma boa coesa biblioteca e a solução.As soluções que você já não se pareciam muito com o C++ mais.
Outras dicas
Como para o modelo de agente, há implementações existentes como ATO++ e Theron, mas eu não conseguia encontrar qualquer coisa, mas a de artigos sobre o antigo, e o último é single-threaded só.
Como o autor de Theron, eu estava curioso para saber por que você acredita que é single-threaded?
Pessoalmente, eu tenho implementado atores uso de threads e uma thread-safe fila de mensagens
É assim que Theron é implementado..:-)
Ash
Estou actualmente a implementar um ator biblioteca para C++ chamado "acedia" (não há nada ainda sobre isso no google), que usa o "tipo de correspondência".A biblioteca é um projeto para a minha tese de mestrado e que você pode enviar qualquer tipo de dados para um ator com ele.
Um pequeno trecho:
recipient.send(23, 12.23f);
E no lado do destinatário, você pode analisar a mensagem recebida como este:
Message msg = receive();
if (msg.match<int, float>() { ... }
...ou você pode definir um conjunto de regras que invoca uma função ou método para você:
void doSomething(int, float);
InvokeRuleSet irs;
irs.add(on<int, float>() >> doSomething);
receiveAndInvoke(irs);
Também é possível combinar ambos sobre o tipo e o valor:
Message msg = receive();
if (msg.match<int, float>(42, WILDCARD) { ... }
else if (msg.match<int, float>() { ... }
A constante "CURINGA" significa que qualquer valor será acceptet.Passar sem argumentos é igual conjunto de todos os argumentos para "UNIVERSAL";o que significa que você só deseja corresponder os tipos.
Este é, certamente, um pequeno fragmento.Você também pode usar a caso "classes", como em Scala.Eles são comparáveis "atômicos" em erlang.Aqui está um exemplo mais detalhado:
ACEDIA_DECLARE_CASE_CLASS(ShutdownMessage)
ACEDIA_DECLARE_CASE_CLASS(Event1)
ACEDIA_DECLARE_CASE_CLASS(Event2)
Para reagir ao caso de classes que você pode escrever um ator parecido com este:
class SomeActor : public Actor
{
void shutdown() { done = true; }
void handleEvent1();
void handleEvent1();
public:
SomeActor() : done(false) { }
virtual void act()
{
InvokeRuleSet irs;
irs
.add(on<ShutdownMessage>() >> method(&SomeActor::shutdown))
.add(on<Event1>() >> method(&SomeActor::handleEvent1))
.add(on<Event2>() >> method(&SomeActor::handleEvent2))
;
while (!done) receiveAndInvoke(irs);
}
};
Para criar um novo ator e iniciá-lo, tudo que você tem para escrever é:
Acedia::spawn<SomeActor>();
Apesar de a biblioteca não chegou até mesmo a versão beta do estádio mostrados trechos de trabalho e eu tenho uma primeira aplicação em execução.Um dos principais objetivos da biblioteca é de suporte de programação distribuída (também através de uma rede).
Sua pergunta é há um tempo atrás, mas se você estiver interessado em:deixe-me saber!:)
Você pode imitar o comportamento usando Qt signal/slot mecanismo, especialmente desde Qt signal/slot suporta multitarefa.
Eu com certeza gostaria de estar interessado em olhar para o seu "acedia" biblioteca e gostaria de ajudar de alguma maneira que eu podia.Erlang tem algumas maravilhosas construções e C++ definitivamente poderia beneficiar de uma biblioteca.
Hoje eu hostet a biblioteca no sourceforge: https://sourceforge.net/projects/acedia/
Como eu disse antes, é uma versão inicial.Mas sinta-se livre para criticá-lo!
Hoje, se você quiser erlang estilo robusto atores em C++, e a correspondência de padrões, talvez a Ferrugem é a resposta.
É claro que isso não estava em torno publicamente quando o OP pediu ~5 anos atrás, e a partir de abril de 2014 ainda não é v1.0, mas foi progredindo muito bem e é, definitivamente, a estabilização, o suficiente da língua de núcleo é estável, eu acho.
E ok não é C++, mas tem a mesma abordagem para o gerenciamento de memória como C++, exceto que ele suporta leve tarefas sem memória compartilhada por padrão (em seguida, fornece controlada biblioteca de recursos para partilha - "Arco");Ele pode chamar diretamente (e expor diretamente) 'extern C" de funções.Você não pode compartilhar modelo de biblioteca de cabeçalhos com C++, mas você pode escrever genéricos que simular C++ classes de coleção (e vice versa) para passar referências a dados-estruturas de todo.