2010-01-20 15 views
5

Attualmente sto cercando di imparare il networking con Python asyncore e pyqt4.QObject (QPlainTextEdit) e problemi di multithreading

Ho codificato un piccolo server, che in pratica ascolta alcune porte e invia di nuovo tutti i messaggi ricevuti al mittente.

Poiché entrambe qt QApplication.exec_() e asyncore.loop() sono funzioni che non ritorno ho non entrambi potuto iniziare in un thread, così fissai asyncore.loop() in un thread daemon separato.

Ogni volta che la mia classe di server (derivato da asyncore.dispatcher) stabilisce o elimina un collegamento, o invia/riceve un messaggio, chiama i metodi della mia classe di finestra (derivato da QtGui.QMainWindow), che visualizza le informazioni in un QPlainTextEdit.

Ma il testo non è visibile, a meno che non si contrassegna il testo con il mouse.

Python console display seguenti msg di errore:

QObject::connect: Cannot queue arguments of type 'QTextBlock' 
(Make sure 'QTextBlock' is registered using qRegisterMetaType().) 
QObject::connect: Cannot queue arguments of type 'QTextCursor' 
(Make sure 'QTextCursor' is registered using qRegisterMetaType().) 

ho letto su alcuni forum, che questo può essere causato da chiamando qt-funzioni da un altro thread, e che utilizzano segnali & fessure al posto della funzione pianura chiamata può risolvere il problema, ma ho provato anche i segnali, e ho ancora questo errore.

Quindi, (se questo è davvero la causa dei miei problemi) qual è il modo corretto per chiamare i metodi di un oggetto qt da un altro thread?

EDIT Ulteriori informazioni: l'asyncore.loop() chiamata si trova nel thread figlio, così non è davvero il blocco, ma solo durante il tempo di esecuzione asyncore.loop() mia classe Server (asyncore.dispatcher) può fare networking. Quindi, durante il runtime di asyncore.loop() i metodi della mia classe Server sono chiamati da asyncore.loop() (= thread figlio), e in questi i ha provato ad emettere segnali alla classe della finestra in esecuzione nel thread principale

EDIT: Sembra che l'ho fatto funzionare ora, ho avuto alcuni errori nel mio codice, tutto funziona come previsto con i segnali ora.

EDIT: piccolo esempio: http://paste2.org/p/635612 (link morto)

+0

Puoi pubblicare una spiegazione o uno snippet della soluzione di lavoro? Sicuramente aiuterebbe gli altri con lo stesso problema in futuro. =) –

risposta

8

Sembra che stai cercando di accedere alle classi QtGui da un thread diverso dal thread principale. Come in altri toolkit della GUI (ad esempio Java Swing), ciò non è consentito. Dalla pagina web Threads and QObjects:

Anche se QObject è rientrante, le classi GUI , in particolare QWidget e tutti i suoi sottoclassi, non sono rientranti. Loro possono essere utilizzati solo dal thread principale.

Una soluzione consiste nell'utilizzare segnali e slot per la comunicazione tra il thread principale (dove vivono gli oggetti della GUI) e il/i thread secondario/i. Fondamentalmente, si emettono segnali in un thread che viene consegnato a QObjects tramite l'altro thread. La pagina che ho collegato sopra ha una buona discussione di questo. In realtà, l'intera sezione su Thread Support in Qt è una buona lettura.

Un potenziale problema che si potrebbe incontrare è che, normalmente, per ottenere segnali completi e gli slot supportano i thread, è necessario avviare un ciclo di eventi nel thread secondario usando QThread::exec() (o l'equivalente PyQt) in modo che i segnali possano essere consegnato agli slot nei QObjects che vivono lì. Nel tuo caso, sembra che tu stia effettuando una chiamata di blocco a asyncore.loop(), il che ti impedirà di farlo. Ma se hai solo bisogno di emettere segnali in una direzione (dal thread secondario ai widget nel thread principale), non penso che avrai un problema.

+1

I messaggi di errore indicano che tenta di stabilire una connessione segnale/slot. Tuttavia, il tipo di dati QTextBlock non è un QMetaType registrato e pertanto non può essere trasportato dalle connessioni tra i thread. – e8johan

+0

Ho completamente dimenticato di provare QThread ... ma come posso usare QThreads per il mio problema ??, dal momento che QThreads 'exec() _' metodo è di nuovo un metodo di blocco, quindi non posso eseguirlo nello stesso thread come la mia classe Server .
@ e8johan: ho ricevuto gli stessi messaggi di errore quando non usavo i segnali .. – smerlin