2013-05-16 1 views
7

Attualmente sto usando Visual C++ per provare a collegare le funzioni di lua come callback per gli eventi socket (in un altro thread). Inizializzo le cose di lua in un thread e il socket è in un altro thread, quindi ogni volta che il socket invia/riceve un messaggio, chiamerà la funzione lua e la funzione lua determina cosa dovrebbe fare secondo il 'tag' all'interno del Messaggio.È in grado di chiamare una funzione lua (come una richiamata) da un altro thread abbastanza sicuro?

Quindi le mie domande sono:

  1. Dal momento che passare lo stesso Stato Lua alle funzioni lua, è sicuro? Non ha bisogno di un po 'di protezione? Le funzioni lua sono chiamate da un altro punto quindi suppongo che possano essere chiamate simultaneamente.

  2. Se non è sicuro, qual è la soluzione per questo caso?

risposta

2

Non è sicuro richiamare in modo asincrono in uno stato Lua.

Ci sono molti approcci per affrontare questo. I più popolari riguardano una sorta di sondaggio.

Un recente libreria di sincronizzazione generica è DarkSideSync

Un popolare Lua vincolante per libev è lua-ev

This SO answer raccomanda Lua Lanes con LuaSocket.

+0

Potrebbe spiegare la differenza tra Luan Lanes e DarkSideSync? DarkSideSync ha piccoli esempi e non so come usare DarkSideSync –

+1

Lanes fornisce un tipo di dati, Lindas, che può essere condiviso in modo sicuro tra le Lanes, stati Lua asincroni. DarkSideSync è più focalizzato sulla notifica e la comunicazione tra Lua e le librerie C asincrone. –

+0

Grazie Doug. –

1
  1. Non è sicuro chiamare la funzione all'interno di uno stato Lua contemporaneamente in più thread.

  2. Mi stavo occupando dello stesso problema, poiché nella mia applicazione tutte le basi come la comunicazione sono gestite da C++ e tutta la logica aziendale è implementata in Lua. Quello che faccio è creare un pool di Lua che sono tutti creati e inizializzati su base incrementale (una volta che non ci sono abbastanza stati, creane uno e inizializza con funzioni/oggetti comuni). Funziona così:

    • volta una filettatura deve chiamare una funzione Lua, si estrae un'istanza di stato Lua, inizializza globali specifici (I chiamo un contesto filo/connessione) in un separato (proxy) tabella globale che impedisce l'inquinamento globale originale, ma è indicizzato dal globale originale
    • Chiama una funzione Lua
    • Controllare lo stato Lua nella piscina, dove viene ripristinato lo stato "pronto" (smaltire il tabella globale del proxy)

Penso che questo approccio sarebbe adatto anche per il tuo caso. Il pool controlla ogni stato (a intervalli) quando è stato effettuato l'ultimo checkout. Quando la differenza di orario è abbastanza grande, distrugge lo stato per preservare le risorse e regolare il numero di stati attivi sul carico del server corrente. Lo stato che viene estratto è l'ultimo utilizzato tra gli stati disponibili.

ci sono alcune cose che dovete considerare in sede di attuazione di tale piscina:

  • Ogni stato ha bisogno di essere popolato con le stesse variabili e funzioni globali, che aumenta il consumo di memoria.
  • Implementazione di un limite massimo per il conte stato in piscina
  • Garantire tutte le variabili globali in ogni stato sono in uno stato consistente, se capita di cambiare (qui mi sento di raccomandare la precompilazione globali solo statiche, durante il popolamento quelle dinamiche durante il controllo out a state)
  • Caricamento dinamico delle funzioni. Nel mio caso ci sono molte migliaia di funzioni/procedure che possono essere chiamate in Lua. Averli costantemente caricati in tutti gli stati sarebbe un enorme spreco. Quindi, invece, mantengo il loro codice byte compilato sul lato C++ e li carico quando necessario. Si scopre che non influisce molto sul rendimento nel mio caso, ma il tuo chilometraggio può variare. Una cosa da tenere a mente è caricarli solo una volta. Supponiamo che tu invochi uno script che deve chiamare un'altra funzione caricata dinamicamente in un ciclo. Quindi dovresti caricare la funzione come locale una volta prima del ciclo. Farlo diversamente sarebbe un enorme successo per le prestazioni.

Naturalmente questa è solo un'idea, ma che si è rivelata la più adatta per me.

+0

Sembra una buona idea. Ma qualsiasi codice open source/condiviso se possibile? –

+0

@MickeyShine - Non posso darti tutto ciò che è stato realizzato da Lua, ma potresti dare un'occhiata all'implementazione di mysql ++ 'dei pool di connessioni, che funziona più o meno come si deve. [Connection Pool] (http://tangentsoft.net/mysql++/doc/html/refman/classmysqlpp_1_1ConnectionPool.html) –

1
  1. non è sicuro, come gli altri citati
  2. dipende dal vostro caso d'uso

soluzione più semplice utilizza un blocco globale utilizzando le lua_lock e lua_unlock macro. Quello userebbe un singolo stato Lua, bloccato da un singolo mutex. Per un numero basso di callback potrebbe essere sufficiente, ma per un traffico più elevato probabilmente non sarà a causa del sovraccarico sostenuto.

Una volta che si ha bisogno di prestazioni migliori, il pool di stato Lua come menzionato da W.B. è un bel modo per gestire questo. Trickiest part qui trovo la sincronizzazione dei dati globali attraverso gli stati multipli.

DarkSideSync, indicato da Doug, è utile nei casi in cui il ciclo principale dell'applicazione risiede sul lato Lua. L'ho scritto appositamente per questo scopo. Nel tuo caso questo non sembra un adattamento. Avendolo detto; a seconda delle esigenze, potresti prendere in considerazione di cambiare la tua applicazione in modo che il ciclo principale risieda sul lato Lua. Se si gestiscono solo socket, è possibile utilizzare LuaSocket e non è richiesta alcuna sincronizzazione. Ma ovviamente questo dipende da cos'altro fa l'applicazione.