È possibile implementare il sondaggio con QThread senza sottoclassirlo?
-
28-10-2019 - |
Domanda
Ho una classe, che è un'astrazione di alcuni dispositivi.
class Device
{
public:
...
void Start();
void Stop();
void MsgLoop();
signals:
void sMsgArrived();
}
Start () e stop () sono chiamati dal thread GUI. Start () inizia un nuovo thread, che esegue msGloop (). Sembra questo:
void MsgLoop()
{
forever {
if(SUCCESS == ReadMsg()) //synchronous, non-blocking
{
ProcessMsg(); //quite fast
emit sMsgArrived(); //this signal is connected with a slot in GUI thread
}
}
}
Quando viene chiamato stop (), il programma dovrebbe tornare da msGloop () e arrestare il thread. Come posso implementarlo con QThread senza sottoclassirlo?
Soluzione
Generalmente devi decidere chi sarà responsabile della gestione del thread. È il dispositivo o la finestra principale? O forse un gestore di dispositivi. Nel tuo caso il dispositivo dovrebbe probabilmente gestire il proprio thread, quindi se non si desidera sottoclassare, utilizzare la composizione:
class Device : QObject
{
Q_OBJECT
public:
Device(QObject * parent = NULL);
void Start();
void Stop();
private slots:
void MsgLoop();
signals:
void sMsgArrived();
private:
QThread thread;
bool stopThread;
};
Device::Device(QObject * parent) : QObject(parent)
{
moveToThread(&thread);
connect(&thread, SIGNAL(started()), this, SLOT(MsgLoop()));
}
void Device::Start()
{
stopThread = false;
thread.start();
}
void Device::Stop()
{
stopThread = true;
thread.wait(); // if you want synchronous stop
}
void Device::MsgLoop()
{
// your loop
while(!stopThread)
if(SUCCESS == ReadMsg())
{
ProcessMsg();
emit sMsgArrived();
}
QThread::currentThread->quit();
}
Nota: la fermo thread funzionerà solo se ReadMsg
davvero non blocca. Se in seguito decidi di passare al blocco della lettura (e questo sarebbe probabilmente appropriato per la maggior parte dei casi), dovrai capire un altro modo per fermare il thread.
Altri suggerimenti
Se guardi questo collegamento Puoi vedere che è possibile eseguire un metodo in un thread separato senza sottoclasse un QThread.
Tuttavia, quello che stai chiedendo è eseguire un ciclo di messaggi per sempre.
Se segui l'esempio fornito puoi eseguire il tuo loop senza la sottoclasse ma l'oggetto QThread non entrerà mai nel suo proprio ciclo di messaggi Perché non tornerà mai dallo slot. Quindi ecco un esempio ma penso che sarebbe un cattivo disegno
class Device : public QObject
{
Q_OBJECT
public:
Device(QObject* parent = 0);
~Device();
public Q_SLOTS:
void MsgLoop();
};
QThread* thread = new QThread;
Device* device = new Device;
void Widget::onBtnStartClicked()
{
device->moveToThread(thread);
//This will call start method of Device
connect(thread, SIGNAL(started()), device, SLOT(MsgLoop()));
//This will start the event loop of thread
thread->start();
}
void Widget::onBtnStopClicked()
{
//Tells the thread to exit
thread->exit(0);
}
Temo che tu debba sottoclasse un QThread se vuoi eseguire un per sempre ciclo continuo.
Imho non dovresti. Il sondaggio richiede di essere in un ciclo per sempre. È necessario farlo nella funzione di corsa di QThread, quindi non c'è modo di reimplementare una funzione senza prima sottoclasse. Anche se dovessi provare a lavorare con un singolo timer, non lo consiglio. Stai meglio (è così che mi piace farlo) sotto-classicante QThread, chiamando MoveTothRead (), non Call Exec () e metti un giro per sempre in corsa. Per un esempio di questo sguardo all'esempio del client bloccante della fortuna da Qt. Se non si chiama MoveToThRead () su QThread, l'oggetto QThread risiede ancora nel thread principale della GUI ed entrambi condividono lo stesso ciclo di eventi (che è cattivo quando si utilizzano funzioni di polling). Chiamare MoveTothRead (QThread) senza chiamare Exec () significa che QThread non avrà un ciclo di eventi (che è buono nel tuo caso). Calling Exec () inizierebbe il proprio ciclo di eventi ma non è utilizzato per i sistemi di sondaggi e lasci la funzione di corsa.