2012-02-20 22 views
5

Sto utilizzando process-send-string per inviare dati a una connessione socket, ma non sono soddisfatto dell'effetto di questa funzione. Approssimativamente, chiamare (process-send-string "foo") potrebbe finire con l'invio di "bar" e quindi con "foo", come spiegato di seguito.scrittura atomica su una presa

Come rilevato dalla Emacs manutentori, il codice C di process-send-string chiama una funzione wait_reading_process_output (anche prima di scrivere nulla), che può eseguire temporizzatori, che a sua volta può chiamare process-send-string, e nessun ordinamento viene forzata tra tali chiamate nidificate.

Ciò rende praticamente impossibile l'implementazione di un protocollo RPC che è destinato ad essere utilizzato da hook chiamati a orari incontrollati. Quindi la mia domanda è: come potremmo raggiungere una primitiva di scrittura atomica, "sincronizzata" per questo scopo?

+1

Hai effettivamente provato quell'effetto? Dando uno sguardo al codice sorgente di Emacs, sembra che il caso che descrivi possa sorgere quando i dati non possono essere scritti sul socket in un batch, ma richiede più chiamate a "sendto". Dopo ciascuna di queste chiamate, viene chiamato 'wait_reading_process_output 'per gestire gli eventi della tastiera e il nuovo invio. Non mi è chiaro come i timer usati all'interno di quella funzione possano chiamare di nuovo 'process-send-string '. – Thomas

+0

Sì, ho visto quanto segue: inviando m1, m2, m3, la connessione riceve m2, m3, m1. –

+0

Si noti che TCP è orientato ai byte, non orientato ai pacchetti. Se l'applicazione scrive "1234", lo stack TCP può inviarlo in qualsiasi segmentazione possibile, ad esempio "12", "3", "4". Se si desidera eseguire un protocollo sopra TCP, è necessario trovare definire un modo per trovare i limiti dei messaggi, ad es. utilizzando un campo di lunghezza. – bew

risposta

1

Infine, un'opzione che ha funzionato per me era utilizzare l'API della coda di transazione, che è di livello superiore (quindi non può gestire tutti i tipi di protocolli), ma garantisce l'ordine corretto dei messaggi alternativi.

2

Anziché utilizzare la stringa di invio del processo direttamente nei ganci, aggiungere un buffer, quindi eseguire le chiamate di stringa di invio del processo in modo non asincrono.

+1

"le chiamate process-send-string vengono eseguite in modo non asincrono" come? –

3

Si potrebbe fare qualcosa di simile:

(defun my-send-cmd (proc str) 
    (if (process-get proc 'my-waiting) 
     (process-put proc 'my-pending (append (process-get proc 'my-pending) (list str))) 
    (process-put proc 'my-waiting t) 
    (process-send-string proc str))) 

poi nel processo di filtro, quando si ottiene la risposta a un comando, controllare `la mia attesa' e se non nullo, prendere la prima arg, inviarlo al processo, altrimenti impostare il mio-attesa di nuovo a zero. Ovviamente, questo presuppone che ogni comando riceverà una risposta dal server e che non è possibile eseguire lo streaming dei comandi.

Detto questo, il comportamento che si vede dovrebbe probabilmente essere considerato un bug, o almeno una disfunzione, quindi per favore segnalalo con M-x report-emacs-bug.

+0

Sembra funzionare: la comunicazione del protocollo funziona ancora e non posso più osservare le conseguenze di uno scambio di messaggi, quindi suppongo che tu mi abbia appena salvato la vita risolvendo questo importante problema in un'ora dall'invio :-) –

+0

L'idea di usare il filtro di processo come "thread di invio" era ciò che mi mancava, e funziona bene in quanto ho sempre messaggi alternati. –

+0

E a proposito di un bug report, ne ho inviato uno, ho avuto qualche feedback breve, ma non sono ancora sicuro se sia considerato un bug, una disfunzione o nessuno. Mi assicurerò di ottenere una risposta chiara. –