2010-09-20 7 views
5

Sto scrivendo un'estensione C, fornendo un'interfaccia tra Ruby e una libreria I/O asincrona. Durante l'esecuzione dei test oltre il mio codice, ho spesso si verificano errori compresi (ma non limitati a):Come evitare le violazioni cross-thread in un'estensione Ruby?

[BUG] cross-thread violation in rb_thread_schedule() 

asincrona IO significa la mia estensione C avrà bisogno di consegnare i messaggi al rubino da più thread (non il filo interprete principale) . Come evito queste violazioni di sicurezza del thread, nel processo?

+0

Ruby 1.8.xo 1.9.x? – llasram

+0

La mia preoccupazione era 1.8, ma 1.9 è rilevante pure. –

risposta

7

Per ruby ​​1.8.x l'unico modo per evitare l'errore è ovvio: è sufficiente richiamare l'API Ruby/C dal thread dell'interprete principale. Credo che questo valga anche per Ruby 1.9.x, ma non ho lavorato con esso e non so come il suo supporto ai thread nativi possa cambiare le cose. Invece di fare in modo che più thread nativi invochino direttamente l'API, è necessario utilizzare lo schema produttore/consumatore per inviare richieste dai thread nativi secondari al codice nel thread dell'interprete principale. E idealmente fallo mentre non blocchi inutilmente altri thread di Ruby green. Se si osserva l'implementazione di ruby, lo scheduler di thread verde rubino è essenzialmente un ciclo select(). Ciò suggerisce la seguente struttura generale:

  • Creare una pipe o un altro meccanismo IPC che fornisce un vero descrittore di file select() -able.
  • Creazione di thread nativi e fornire loro l'estremità di scrittura del tubo.
  • Nel thread principale dell'interprete, immettere un ciclo eventi che chiama rb_thread_wait_fd() sull'estremità di lettura del tubo. Ciò consentirà allo scheduler di thread verde rubino di eseguire altri thread verdi.
  • Quando i thread nativi secondari hanno richieste per il thread principale, li mettono in coda e scrivono anche nella pipe, svegliando il thread verde che esegue il ciclo degli eventi.

Vedi rb_io_sysread() (attuazione della IO#sysread) per quello che è probabilmente il più semplice pulito IO-usando la funzione nella base di codice Ruby.

Problemi correlati