2010-07-11 15 views
6

Sto guardando la programmazione funzionale e sto lottando con un punto .. Come faccio a fare quanto segue senza lo stato mutabile?Come posso scrivere un server multi-client che non ha lo stato mutabile?

Immagina di avere un server .. e i client provano a collegarsi .. e ogni client assegna al server un numero e viene informato del totale corrente.

Ora senza lo stato mutabile il server non può mantenere un totale ... quindi penso che ogni client stia davvero creando un nuovo server che contiene un nuovo totale .. o un nuovo server che contiene la voce e fa riferimento al vecchio server in modo il totale può essere calcolato.

MA ... come fa il client a trovare il server? Qualcuno deve mantenere l'istanza del server corrente ... quindi hanno una variabile mutabile 'server'.

Non importa quello che faccio .. Finisco sempre con una variabile mutabile un ambito più alto.

Pensieri?

risposta

5

Lo scenario che descrivi potrebbe essere implementato come questo (pseudocodice):

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

let main() = keepTrackOfTotal(0) 

Qui si usa la ricorsione per ottenere un ciclo infinito che tiene traccia del totale, senza variabili mutevoli.

+0

Posso vedere come funzionerebbe con più client sequenziali. Funzionerebbe in un sistema parallelo multicore? Questo lo costringe a essere sequenziale? –

+0

Impone che sia sequenziale, poiché può gestire solo una connessione alla volta. Il problema quindi con multicore è che si potrebbe rifiutare una connessione (s). Spesso hai un qualche tipo di meccanismo per affrontarlo. Il meccanismo di Erlang è di far passare tutti i client al server un messaggio che viene inserito in una coda per l'elaborazione. Non è l'unico modo, anche se non ho molta familiarità con gli altri. –

+0

È interessante notare che questa è una soluzione circolare poiché lo stack è uno stato mutabile non appena si hanno due client per il proprio stack (ad esempio uno spintore e un estrattore) ... perché gli stack immutabili producono nuovo stack quando si spinge o si fa pop ... quindi come possono entrambi lo spintore e l'estrattore parlare alla stessa coda. :) –

3

Almeno in Erlang il modo in cui è fatto è che il processo stesso ha un nome.

Così mentre il loop del server avvia costantemente nuove versioni di se stesso (chiamando la stessa funzione alla fine della chiamata, come nell'eccellente pseudocode di sepp2k) e inserendo la somma come parametro, tutti i client stanno contattando processo per nome, in modo che possano ancora trovarlo.

0

Qualcosa come questo (in C++). Abbiamo assistente puntatore statico, ogni istanza di oggetto server è immutabile

#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; 

Ogni chiamata del getInstance() restituisce dell'oggetto Server immutabile. È possibile chiamare il metodo GetTotal() quando un altro thread funziona nel metodo Aggiungi.

+1

Non hai davvero ottenuto attorno alla mutevolezza però. L'hai appena spostato dall'avere una variabile 'total' mutabile ad avere una variabile' server' mutabile. – sepp2k

Problemi correlati