I'm trying to write an app for testing ST board via serial port and I'm currently facing the following issue. (The code below is just a simplification of a problem.)
Widget::Widget(QWidget *parent)
: QWidget(parent)
, m_button(new QPushButton(this))
, m_timer(new QTimer(this))
{
m_timer->setSingleShot(true);
connect(m_button, &QPushButton::released, this, &Widget::RunTest);
connect(m_timer, &QTimer::timeout, this, &Widget::OnTimeout);
}
void Widget::RunTest()
{
qDebug() << "Start test";
m_timer->start(1000);
while (m_timeout != true);
qDebug() << "Start end";
}
void Widget::OnTimeout()
{
qDebug() << "Timeout";
m_timeout = true;
}
I want to have a seprate class for gathering and running tests. The tests are triggered by clicking on a button. Some tests will have to send data via serial port and wait for the reply. I would like to be able to implement a timeout feature (if board doesn't reply then finish test with failure). However I the app is waiting for the m_timeout flag indefinitely. So my question is: Is there any signal/slot mechanism similar to interrupt preemption? If no how sush problems are solved in Qt? Shall I create seprate QTimer object and run it in separate thread?
Related
I'm using QtConcurrent::run to execute some functions in background and not hang the GUI thread. In one function, I read logs from local SQlite database and send them to server by TCP socket.
Now I want to delay the execution after each log so the server has time to save it (TCP response is read in different thread). I'm stuck with Qt4.8 due to implementation limitations (many embeded devices - no chance to upgrade QT on them) and I can't use QThread::sleep(2) because it is protected in 4.8.
Is it possible to somehow pause the execution of thread inside QtConcurrent::run method or should I redesign it to implement my own class inheriting QThread?
void MainWindow::ReportFinishedHUs(bool asyncWork)
{
if(asyncWork == false)
{
QMutexLocker locker(&localDBmutex);
QList<QSqlRecord> HUsToReport = localDB->getHUsForBook();
qDebug() << "HUs to report" << HUsToReport.count();
if(!HUsToReport.isEmpty())
{
Cls_log::WriteDebugLog("HUs to report: " + QString::number(HUsToReport.count()));
foreach (QSqlRecord record, HUsToReport)
{
int _hu = record.indexOf("hu");
int _logTime = record.indexOf("logTime");
QString logTimeString = record.value(_logTime).toString();
QString hu = record.value(_hu).toString();
qDebug() << hu << logTimeString;
// creating message here ...
qDebug() << message;
emit sig_SendTCPMessage(message);
// this is where I need to wait for 2 seconds
QThread::sleep(2);
}
}
}
else
{
QtConcurrent::run(this, &MainWindow::ReportFinishedHUs, false);
}
}
EDIT:
Solved by usleep(2000000) which I somehow discarded for being platform specific... but hey, half of my aplication is platform specific and I only use it in embeded device with constant OS.
Keeping the question open if anyone can suggest more elegand solution using Qt methods. I like to get inspired.
I have problem with synchronize(start at the same time QTCPSocket) in my application I have 10 sockets. I have to read data at the similar time to all sockets. At this moment I have something that:
///...///
if(!socket->waitForConnected(-1))
{
qDebug() << "Server not found";
emit serverNotFound();
}else if(socket->state()==QAbstractSocket::ConnectedState){
qDebug() << "Connected"
connect(timer, SIGNAL(timeout()),this,SLOT(connected()));
timer->start(1000);
}
}
On connected signal:
void SocketsClass::connected()
{
sendRequest(socket, messageToServer);
}
The problem is that when the first socket get connected the timer starts for the one.
You can invert your approach. Don't wait for the sockets to get connected. Instead, check if the socket is connected in the slot activated by the timer. In that slot, you can iterate over all sockets and send the message to each of them.
Finally, you should never use Qt's waitForXxx methods, they lead to a horrible pseudo-synchronous code that is very error prone and hard to extend and maintain. Use the signal-slot mechanism instead.
Example:
SocketManager : public QObject {
Q_OBJECT
QTcpSocket m_sockets[10];
QTimer m_timer;
public:
SocketManager(QObject * parent = 0) : QObject(parent) {
... // connect all sockets here
m_timer.start(1000);
connect(&m_timer, &QTimer::timeout, [this]{
for (auto & socket : m_sockets)
if (socket.state() == QAbstractSocket::ConnectedState)
sendRequest(socket, messageToServer);
});
}
};
Okay, so, here's the deal.
I'm currently writing a small chat messaging simulation / project using SysV IPC, and I use Qt for my client app. What I want is a background thread that would wait on a message queue and send a signal to a GUI thread whenever a new message comes. I have attempted to write the code using QThread inheritance, but it doesn't seem to work, the messages are not shown, and I think I'm missing something here.
As for the code:
ipcEventListener.h:
class IPCEventListener : public QThread
{
Q_OBJECT
public:
IPCEventListener();
void run();
messageWrapper mw;
signals:
void sendChatMsg(MSG_CHAT_MESSAGE cm);
};
ipcEventListener.cpp
IPCEventListener::IPCEventListener()
{
}
void IPCEventListener::run()
{
mutex.lock();
int n = msgrcv(myQueueId, &mw, sizeof(mw)-sizeof(long), 0, IPC_NOWAIT);
mutex.unlock();
if (n>0)
{
snip...
else if (mw.resp.type == MESSAGE)
{
emit sendChatMsg(mw.chatMsg);
}
}
exec();
}
mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
listener = new IPCEventListener(this);
connect(this->listener, SIGNAL(sendChatMsg(MSG_CHAT_MESSAGE)), this, SLOT(message_received(MSG_CHAT_MESSAGE)));
connect(this->ui->pushButton, SIGNAL(clicked()), this, SLOT(on_pushButton_clicked()));
listener->start();
ui->comboBox->addItem("Client");
ui->comboBox->addItem("Room");
}
void MainWindow::message_received(MSG_CHAT_MESSAGE cm)
{
QString formattedMessage = "";
formattedMessage.append("[");
formattedMessage.append(cm.send_time);
formattedMessage.append("] ");
if (cm.msg_type == PRIVATE) formattedMessage.append("[PRIV:] ");
formattedMessage.append(cm.sender);
formattedMessage.append(": ");
formattedMessage.append(cm.message);
formattedMessage.append("\n");
ui->textEdit->append(formattedMessage);
}
What am I missing?
(PS: I know the code probably breaks about a hundred thousand of code conventions, but the deadline is pretty soon and I have to resort to kludges. It's just a school project, though).
You have a logical error in your code. You treat void IPCEventListener::run() as a method which is in a loop and is executing again ang again ang again but it's not. QThread::run() is method where you only initialize your thread and execute exec() function, to start event loop. It means that in current version of your application, you try to receive message just once and then your thread is just waiting for some events, without doing anything with them.
So what you need is an inifite loop in which you will try to receive messages. And don't forget to stop this loop while program closing.
I have the following code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
qApp->processEvents();
processmethodONE();
processmethodTWO();
processmethodTHREE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessCommand);
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
In this source code I try to open a popup dialog before some processes are starting. problem is that the dialog is not clickable, but on the dialog I want to create a button to abort the running method. As you can see I tried using QThread to run the process(es) in another thread, but still I can't click the dialog. Furthermore if I open my application (GUI) with the "application/x-executable"-file the dialogs content is missing when activating the above shown method. How can I fix these problems? Where am I wrong? greetings
void processmethodONE()
{
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessComand);
Here you moved the QProcess to another thread. But then you call start() on it. That's already not thread-safe.
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
This blocks and makes using a thread useless. Also, it's not thread-safe.
You should instead not use threads but:
remove the waitForFinished() call
Connect the finished() and error() signals of the QProcess to slots which then start the next step, i.e. processMethodTWO.
I would also advise against reusing QProcess objects and just create a new one for each step.
While I still don't fully understand your recently updated code example, I feel this might be your issue:
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
Wherever you are really calling this in your original code is blocking while waiting for Prozess to finish.
Use a brand new QProcess instance for each one, and connect their finished() signals to a SLOT that will get called when they have finished. Don't manually poll them and block. This will allow you to completely get rid of QThreads altogether.
I've this code here in a program I'm making but I've a problem, How can I keep the program waiting for data on http2 before returning to the tcpserver class? And how can I get the data in the tcpserver class?
This is like a checkpoint were I need to get the data from the server and then keep running the tcpserver and use that data there.
tcpserver.cpp
#include "tcpserver.h"
#include "protocol.h"
#include "http2.h"
QTextStream in(stdin);
tcpserver::tcpserver(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
[ ... Other Server Stuff ... ]
http2 *h = new http2(this);
}
I've tried this with no luck:
http2.cpp
#include "http2.h"
bool httpdonne = false;
QByteArray finaldata;
http2::http2(QObject *parent, QByteArray url, QByteArray data) :
QObject(parent)
{
url.append(data);
m_manager = new QNetworkAccessManager(this);
connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(httpdown(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl(url));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
m_manager->get(request);
while ( httpdonne == false ) {
}
finaldata.append("HTTP: ");
qDebug() << finaldata;
}
QByteArray http2::httpdown(QNetworkReply* result)
{
QByteArray data = result->readAll();
finaldata = data;
httpdonne = true;
return data;
}
Thanks a lot! ;)
Qt makes use of signals and slots and the event loop. If you have no QEventLoop running which is normally provided by QApplication your events will not be handled.
Take a peek at this question to see how to create an event loop to simulate a blocking (synchronous) using the asynchronous programming model.
In addition I normally add a QTimer too:
QEventLoop loop;
..
QTimer timer;
timer.setInterval(2000);
timer.setSingleShot(true);
loop.connect(&timer, SIGNAL(timeout()), SLOT(handleTimeout()));
timer.start();
..
//Setup your objects / connections here...
..
loop.exec(); //Your signals and slots will be triggered / handled now!
Qt network classes are all signal-driven. That is, you create functions which handle various events (data ready etc) and connect them to the appropriate slots. Blocking isn't really the way they are to be used.
Of course I would never recommend what you are trying to achieve but if you still wanna "shoot yourself in the foot" :) then here's what you can try,
run the manager as a separate thread and make the http2 or tcpserver thread wait on
a condition variable. And when the manager is done invoke the threads
waiting the the condition variable.
You can use my WaitForSignalHelper class posted here , it does what you want: wait for a timeout OR signal to be emitted...