2010-06-27 17 views
7

Sto costruendo un piccolo server Web con multithreading. I QTcpSocket vengono recuperati nel thread principale e quindi trasferiti da QtConcurrent a QThreadPool, che alla fine elabora i dati e invia una risposta.Come eseguire QObject :: moveToThread() quando si utilizza QThreadPool?

mio problema è che la presa viene creato nel thread principale ed elaborati in un altro. Questo fa sì che gli errori quando si cerca di scrivere nel socket:

socket->write(somedata); 

QObject: Impossibile creare bambini per un genitore che si trova in un thread diverso. (Parent è QNativeSocketEngine (0x608330), filo genitore è QThread (0x600630), thread corrente è QThread (0x505f60)

pulita modo sarebbe per spostare l'oggetto presa al filo lavorazione utilizzando

socket->moveToThread(QThread::currentThread()). 

Questo, tuttavia, può essere chiamato solo all'interno del filo l'oggetto è stato creato in. Inoltre, la presa ha l'oggetto QTcpServer come genitore, così moveToThread() fallirà comunque (oggetti parented non possono passare fili).

Come posso spostare l'oggetto nella QThread :: currentThread() all'interno del codice che viene eseguito dal ThreadPool? In alternativa, come posso scrivere su un socket al di fuori del thread che è stato creato?

risposta

4

Estendere QTcpServer, reimplementare incomingConnection(int socketDescriptor) e passare il descrittore di socket alle filettature in piscina. Avere la QRunnable creare il QTcpSocket dal descrittore e avviare un ciclo di eventi per ricevere i segnali di quel socket.

0

Bradley Hugues ha scritto un post su Labs Qt parlare di questo argomento, forse questo ti aiuterà un po '!

http://blog.qt.digia.com/2010/06/17/youre-doing-it-wrong/

+0

Grazie, lo so questo post. In effetti lo sto facendo esattamente in questo modo al momento, ma questo non funziona con un pool di thread, che mi piacerebbe utilizzare. Quando si distribuisce il lavoro su più thread, si finisce comunque con la programmazione di un battistrada, quindi perché non utilizzare quello esistente? :) – grefab

0

Sono inoltre d'accordo che catturare incomingConnection(int) e creare il socket nel thread di lavoro sia la strada da percorrere qui.

Ma il problema era una più fondamentale, così mi permetta di mostrare un'alternativa che risolve il problema generale (movimento arbitrari QObject s a fili in un pool di thread):

  1. Nel thread principale: dissociare la presa da qualsiasi thread:

    socket-> moveToThread (nullptr);

    Questo sospenderà elaborazione degli eventi della presa. Quindi passa a QtConcurrent.

  2. Nella funzione eseguita sul pool di thread, è possibile ora chiamare

    socket-> moveToThread (QThread :: currentThread());

    Questo riavvierà l'elaborazione degli eventi.

Con po 'di fortuna, la presa avrà i suoi notificanti presa ri-registrati con ciclo di eventi del thread di lavoro di nuovo, e si può servire la connessione da parte del lavoratore.

Ci sono due avvertimenti importanti qui, però:

  • Non si dovrebbe mettere il blocco compiti sul pool di thread globale (QThreadPool::globalInstance()). Come il nome della funzione suggerisce, l'istanza thread pool è una risorsa globale condivisa da tutti gli utenti di QtConcurrent, e bloccando i suoi thread di lavoro nel migliore dei casi riduce la capacità (quindi, il throughput) della piscina e, nel caso peggiore volontà dead-lock.
  • Se si utilizza il ciclo degli eventi di thread di lavoro (di non utilizzare l'API sincrona di QTcpSocket, a causa del primo punto), avresti bisogno di chiamare QThread::currentThread()->exec() per avviarlo. Tuttavia, si tratta di una chiamata di blocco e del programma di pianificazione del pool di thread, il lavoratore sembrerà occupato, quindi non gli passerà più attività (ad esempio, QRunnable s).

Se si desidera implementare un server TCP a più thread, sarà quindi necessario eseguire il rollup del pool di thread.

Problemi correlati