2015-12-21 15 views
5

Ho letto l'uso di stateful_actor sotto examples/curl/curl_fuse.cpp e libcaf_core/test/stateful_actor.cpp. Sembra che lo stateful_actor<State> possa associare alcuni stati per l'attore dichiarando i campi in State struct. E 'molto utile.Capire lo stateful_actor

Possiamo dichiarare gli stati come campi in class-based actor per ottenere gli stessi effetti? O c'è qualche trattamento speciale nel stateful_actor (ad esempio accesso alla sicurezza del thread)?

Gli attori nel seguente esempio forniscono la stessa funzionalità?

/* Class based actor */ 
struct ClassCounter : caf::event_based_actor 
{ 
    caf::behavior make_behavior() override { 
     return { 
      [=](inc_atom){ i += 1; } 
      , [=](ret_atom){ return i; } 
     }; 
    } 

    const char* name() const override { return "I am class-based"; } 
    int i = 0; 
}; 

/* Stateful actor */ 
struct CounterState 
{ 
    caf::local_actor* self; 
    int i = 0; 
    const char* name = "I am stateful"; 
}; 

caf::behavior StatefulCounter(caf::stateful_actor<CounterState>* self) 
{ 
    return { 
     [=](inc_atom){ self->state.i += 1; } 
     , [=](ret_atom){ return self->state.i; } 
    }; 
}; 

risposta

5

Possiamo dichiarare gli stati come campi in class-based actor per ottenere gli stessi effetti? O c'è qualche trattamento speciale nel stateful_actor (ad esempio accesso alla sicurezza del thread)?

Il runtime di CAF presuppone che gli attori siano isolati, vale a dire, solo un attore stesso è autorizzato ad accedere al suo stato. Quindi, l'accesso allo stato di un attore non è mai sincronizzato. La comunicazione tra attori utilizza il passaggio dei messaggi, evitando così le condizioni di gara in base alla progettazione.

Gli attori di stato consentono ai programmatori di scrivere meno classi (e quindi meno codice boilerplate), ma c'è anche una differenza notevole tra ClassCounter e StatefulCounter: durata delle variabili. In ClassCounter, la variabile membro i è attiva finché non viene chiamato il distruttore di ClassCounter. Poiché gli attori sono conteggiati con riferimento, il distruttore viene eseguito se non viene lasciato alcun riferimento ad esso, ovvero, non esiste una maniglia actor o actor_addr per l'attore. In StatefulCounter, il membro CounterState viene creato se l'attore viene inizializzato e distrutto se termina.

Lo stato esiste solo finché un attore è vivo. Questo è particolarmente utile per i cicli di rottura. Se si dispone dei due attori A e B, si ha un ciclo se A contiene un riferimento a B tramite una variabile membro e viceversa. L'uso di attori di stato invece interrompe questo ciclo. A rilascerà automaticamente il suo riferimento a B all'uscita e viceversa.

+0

Quindi il distruttore del CounterState verrà chiamato quando l'attore termina? –

+0

mm. Penso che separare le preoccupazioni dello stato e il comportamento degli attori sia meglio per la manutenzione. –

+1

"Quindi il distruttore del CounterState verrà chiamato quando l'attore termina?" Sì. Un attore chiude la sua casella di posta e distrugge il suo stato quando termina. Se necessario, attiverà anche i messaggi di uscita o di discesa. Qualsiasi ulteriore messaggio in arrivo verrà eliminato (attivando un messaggio di errore per i messaggi di sincronizzazione) e il collegamento a un attore terminato attiverà immediatamente il messaggio di uscita. – neverlord