2015-04-04 5 views
8

Ho iniziato a utilizzare Qt5 pochi giorni fa. Avevo bisogno di un logger per la mia app e ho deciso di utilizzare qDebug, ma sembra che debba essere "reindirizzato" per avere i registri in un file.Qt5: Come usare qDebug() per accedere a un file, applicazione multi-thread

Ho usato qInstallMessageHandler per farlo e ho scritto il mio gestore come illustrato di seguito (ispirato da altre persone qui).

Sembra che funzioni, ma poiché non sono un guru, devo chiedere: È corretto utilizzarlo in un'applicazione multithread o no?

Inoltre, se è ok/sicuro per l'utilizzo in un'applicazione multi-thread, può essere migliorato in qualche modo?
Grazie!

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg) 
{ 
    mutex.lock(); 

    QDateTime dateTime(QDateTime::currentDateTime()); 

    QString timeStr(dateTime.toString("dd-MM-yyyy HH:mm:ss:zzz")); 
    QString contextString(QString("(%1, %2)").arg(context.file).arg(context.line)); 

    QFile outFile("file.log"); 
    outFile.open(QIODevice::WriteOnly | QIODevice::Append); 

    QTextStream stream(&outFile); 
    stream << timeStr << " " << contextString << ": " << msg << endl; 

    mutex.unlock(); 
} 
+0

Quale tipo ha la variabile 'mutex'? –

+0

mutex QMutex statico; // variabile globale –

+0

Per quale sistema operativo stai sviluppando? –

risposta

1

Il tuo approccio è semplice e pulito. Lo terrei così.

C'è una cosa che puoi migliorare: apri il file solo una volta all'avvio dell'applicazione e chiudilo quando chiudi l'applicazione. L'apertura di un file è un'operazione costosa.

È possibile scrivere nello stesso file aperto da più thread, poiché il mutex garantisce che solo un thread scrive nello stesso momento.

+0

Simon, grazie per aver dedicato del tempo e per il vostro consiglio! Vorrei aprire il file solo una volta all'avvio, ma (nel prossimo futuro) ho intenzione di cambiare il nome del file da "file.log" a qualcosa come "gg-mm-aaa.log" ... Sono sicuro di sapere cosa intendo :) Quindi, sarebbe in qualche modo impossibile aprire il file di registro all'avvio dell'applicazione ... Qualche idea/soluzione per questo problema? Grazie in anticipo! –

+0

@groenhen Ti aspetti che l'applicazione venga eseguita più di un giorno? –

+0

Sì, funzionerà senza interruzioni (almeno lo spero :)) –

2

Non si può trovare in qualsiasi parte della documentazione Qt che qDebug è thread-safe. Quindi non è sicuro chiamarlo contemporaneamente da più thread e in effetti si incontrerebbero output misti se non si utilizza un meccanismo di blocco.

Il tuo approccio di blocco sarebbe meglio se si utilizza QMutexLocker in quanto è fortemente raccomandato dalla documentazione Qt:

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg) 
{ 
    QMutexLocker locker(&mutex); 
    ... 
} 

Un secondo approccio è quello di fornire una classe lavoratrice che è dotato di slot per la scrittura del registro. È quindi possibile avere un'istanza di esso in una nuova discussione e chiamare gli slot nel gestore dei messaggi utilizzando QMetaObject::invokeMethod con un tipo di connessione Qt::QueuedConnection. In questo modo, ogni chiamata da ciascun thread verrebbe accodata ed elaborata nel thread di lavoro e probabilmente avrebbe prestazioni migliori poiché tutto il lavoro viene eseguito in un thread separato.

+1

Ma AFAIK, "Locker QMutexLocker (& mutex);" fa lo stesso lavoro di mutex.lock() seguito da mutex.unlock(), l'unica differenza è che non ti devi preoccupare se/quando quella funzione/metodo ha più punti di uscita/ritorno. Il mutex verrà automaticamente sbloccato all'uscita poiché l'armadietto è una variabile automatica. Cordiali saluti, SG. –

+0

BTW: Che dire di "in termini di velocità" ...? Quale esegue più velocemente, mutex lock/unlock() o un meccanismo QMutexLocker? –

+0

Non sono a conoscenza se differiscono in termini di velocità. Ma un secondo approccio è quello di avere un thread di lavoro ed eseguire operazioni lì. Vedi la risposta modificata. – Nejat