2010-07-11 8 views
6

Estoy buscando programación funcional y luchando con un punto ... ¿Cómo hago lo siguiente sin estado mutable?¿Cómo puedo escribir un servidor multicliente que no tiene estado mutable?

Imagine que tengo un servidor ... y los clientes intentan conectarse ... y cada cliente le da un número al servidor y se le informa el total actual.

Ahora, sin estado mutable, el servidor no puede mantener un total ... así que creo que cada cliente está realmente creando un nuevo servidor que contiene un nuevo total ... o un nuevo servidor que contiene la entrada y hace referencia al viejo servidor el total puede ser calculado.

PERO ... ¿cómo el cliente encuentra el servidor? Alguien tiene que aferrarse a la instancia del servidor actual ... por lo que tienen una variable mutable 'servidor'.

No importa lo que haga ... Siempre termino con una variable mutable de mayor alcance.

¿Pensamientos?

Respuesta

5

El escenario que usted describe podría ser implementado como esto (pseudocódigo):

let keepTrackOfTotal(total) = 
    let conn = waitForConnection() 
    let x = readIntFrom(conn) 
    let newTotal = total + x 
    writeIntTo(conn, newTotal) 
    keepTrackOfTotal(newTotal) 

let main() = keepTrackOfTotal(0) 

Aquí se utiliza la recursividad para obtener un bucle infinito que realiza un seguimiento del total, sin variables mutables.

+0

Veo cómo funcionaría esto con múltiples clientes secuenciales. ¿Esto funcionaría en un sistema paralelo multinúcleo? ¿Esto lo fuerza a ser secuencial? –

+0

Obliga a que sea secuencial, ya que solo puede manejar una conexión a la vez. El problema entonces con multinúcleo es que puede rechazar una conexión (s). A menudo tienes algún tipo de mecanismo para lidiar con eso. El mecanismo de Erlang es hacer que todos sus clientes pasen a su servidor un mensaje que se coloca en una cola para su procesamiento. Esa no es la única forma, aunque no estoy muy familiarizado con los demás. –

+0

Curiosamente, esta es una solución circular ya que una pila es un estado mutable tan pronto como tenga dos clientes para su pila (es decir, un empujador y un extractor) ... porque las pilas inmutables producen una nueva pila cuando empuja o estalla ... por lo tanto ¿Cómo pueden el empujador y el extractor estar hablando con la misma cola? :) –

3

Al menos en Erlang la forma en que se hace es que el proceso en sí tiene un nombre.

Así que mientras el bucle del servidor está constantemente iniciando nuevas versiones de sí mismo (llamando a la misma función al final de la llamada, como en el pseudocódigo excelente de sepp2k) y alimentando la suma como parámetro, todos sus clientes se ponen en contacto procesar por nombre, para que puedan encontrarlo.

0

Algo como esto (en C++). Tenemos servidor de puntero estática, cada instancia del objeto de servidor es inmutable

#include <pthread.h> 
#include <iostream> 
#include <stdlib.h> 
#include <memory> 

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; 

class Server 
{ 
public: 
    Server(int n) : m_n(n){} 
    static void Add(int n) 
    {   
     pthread_mutex_lock(&mutex1); 
     std::auto_ptr<const Server> srv(getInstance()); 
     server = new Server(srv->m_n + n); 
     pthread_mutex_unlock(&mutex1); 
    } 
    static int GetTotal() 
    { 
     std::auto_ptr<const Server> srv(getInstance()); 
     return srv->m_n; 
    } 

private: 

    static const Server* getInstance() 
    { 
     if (server == NULL) 
      server = new Server(0); 

     return new Server(server->m_n); 
    } 
    static volatile const Server* server; 
    int const m_n; 
}; 
volatile const Server* Server::server = NULL; 

Cada llamada del getInstance() devuelve el objeto de servidor inmutable. Puede llamar al método GetTotal() cuando otro hilo funciona en el método Agregar.

+1

No conseguiste realmente alrededor de la mutabilidad aquí sin embargo. Acabas de moverlo de tener una variable 'total' mutable a tener una variable' server' mutable. – sepp2k

Cuestiones relacionadas