How to send data to a specific client on a multithreaded server - qt

I am trying to build a multithreaded server. The problem that I am encountering is that the emitted signal sends message to all clients instead to the specific one on a specific thread.
I tried to solve the issue by creating a QList of threads, but how do I connect them specifically?? When signal is emitted, it wakes up all my threads, the problem is getting worse by each connection, since the clients are dynamically allocated as they are connecting.
Code:
void NetworkServer::incomingConnection(qintptr socketDescriptor)
{
QThread *thread = new QThread;
threadhandle *session = new threadhandle;
QObject::connect(this, &NetworkServer::stopped, session, &threadhandle::close);
QObject::connect(this, &NetworkServer::stopped, thread, &threadhandle::quit);
QObject::connect(session, &threadhandle::closed, thread, &threadhandle::quit);
QObject::connect(thread, &QThread::started, this, &NetworkServer::threadStarted, Qt::DirectConnection);
QObject::connect(thread, &QThread::finished, this, &NetworkServer::threadFinished, Qt::DirectConnection);
QObject::connect(thread, &QThread::finished, session, &QObject::deleteLater);
QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
//the problem is here, I can send message to all clients connected, but how to specifiy a thread/client???
QObject::connect(this, &NetworkServer::sendMsgToThread, session, &threadhandle::sendMsgToClient);
thread->start();
session->moveToThread(thread);
QMetaObject::invokeMethod(session, "open", Qt::QueuedConnection, Q_ARG(qintptr, socketDescriptor));
Update - 40 minutes later - Problem solved
I apologize for not providing more details, basically I am building a simple client-server relationship. Message is send from server GUI line in text format to a specific client.
After some thinking I came up with a solution.
so for each new thread, we will append its session to: QList<threadhandle*>sessionList
After that we are going to edit the sendMsgToClient()
// user clicks on Send Message button in GUI
void NetworkServer::sendMsgToClient(int clientNum, QString msg)
{
//connect the signal to a specific thread, clientNum is selected from a table in mainWindow GUI where the NetworkServer class is initiated
QObject::connect(this, &NetworkServer::sendMsgToThread, sessionList.at(clientNum), &threadhandle::sendMsgToClient);
//emit the signal to specific thread
emit sendMsgToThread(clientNum, msg);
//disconnect the signal, since it is no longer needed
QObject::disconnect(this, &NetworkServer::sendMsgToThread, sessionList.at(clientNum), &threadhandle::sendMsgToClient);
}

Hard to say really without MRE that builds and presents your exact problem. But, guessing from context: no clue how NetworkServer::sendMsgToThread or threadhandle::sendMsgToClient are implemented, but I guess you could store the thread ID/index/any other identifier and then pass it to specific thread only, possible via some proxy object?
Point is, sendMsgToThread gets connected to multiple slots, which is probably not what you want; instead those single session-thread pairs need to be somehow distinguished, e.g. by thread ID/its index in list, whatever.
I guess you could wrap the session and thread in some other class, that would be stored (and referred to) by the server by some of the aforementioned IDs, and it would forward the messages to the worker (session) object. But I cannot really tell without at least basic knowledge of your code's architecture.

Related

Send signal data from QMainwindow to QDialog

I am going to send data collected in the QMainWindow to an object of QDialog via signal-slot connections. Here is the relevant code fragment to do this in mainwindow.cpp:
void MainWindow::on_dialogA_clicked()
{
if(dialogA==NULL) dialogA =new MyDialog();
//'this' refers to MainWindow
connect(this,SIGNAL(sendData(QVector<bool>)), dialogA, SLOT(getData(QVector<bool>)), Qt::QueuedConnection);
dialogA->show();
}
However when working with dialogA, it seems that the data are not updated properly and the dialog interface becomes Not responding after while. I wonder if the signal-slot connection above is right or not, or that is the way to have data communication with a QDiaglog.
Two things...first, switch to the modern method of creating signal/slot connections:
connect (this, &MainWindow::sendData, dialogA, &MyDialog::getData, Qt::QueuedConnection);
If there's something wrong with the definition, using this format allows the compiler to catch it rather than a run-time warning. Assuming the parameters are defined correctly, there's nothing wrong with the "connect" statement except that it's in the wrong place, which is the second issue.
Every time the user clicks, an additional connection is being made between your main window and the dialog. Qt doesn't automatically ensure that only one connection is made between a given signal and slot. It'll create as many as you ask it for. The "connect" call should be part of the "if" block:
if (! dialogA)
{
dialogA =new MyDialog();
connect...
}
Depending on how much data is in that vector and what the dialog does with it, if you click enough times, it may be that you're just processing the data so many times that everything slows down tremendously.

How to make the slot associate with QTimer::timeout can be interrupted by any other signal processor(higher priority) and then resume?

To simplify the question, let's say that i have a QTimer, which will trigger its timeout event every 3000ms.
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&](){
// do sth(rely on a public data structure)
});
timer.start(3000);
The operation inside the lambda connected to the timeout event is relied on a public data structure.
And the application hold an QUdpSocket, and connect the readyRead signal with a slot function.
QUdpSocket socket;
socket.bind(45454, QUdpSocket::ReuseAddressHint);
QObject::connect(&socket, &QUdpSocket::readyRead, [&](){
//manipulate the public data structure
}
As you can see, the lambda connected to the readyRead signal manipulate the public data structure that the first lambda rely on.
So my question is, i want the function that connectted to the readyRead signal has the highest "priority", that is, even in the Qt's event loop are dealing with the timeout slot now, it can be interrupted and start the readyRead slot immediately, then after it finish, resume the timeout slot function. Is there any way to do so?
(My homework is to simulate the IEEE802.11 exposed/hidden node problem, it requires that i have to constantly listen the channel before/during sending a packet.)
(Is explicitly call QCoreApplication::processEvent will help?)
I am not familiar with the IEEE802.11 exposed/hidden node problem, however i don't think you can "interrupt" your code as you're describing.
One possible way to handle with this would be running the code for the readyRead and the timeout slots on different threads and then use some kind of synchronisation mechanism (QMutex comes to mind) to access the public data (and get its state).
i.e.
add some kind of uniqueid to identify the public_data current status
timeout_slot will acquire a lock, read the public data in a local copy and release the lock, then continue to manipulate local structure and finally before release would acquire lock again and check that the uniqueid has not been changed, if so commit your work, otherwise you'd have to start over.
readyRead_slot would acquire the lock, update the uniqueid and then continue working

Qt Communication betwen threads, app design

I'm working on an app which does some TCP communication, uses a database and has a GUI (pretty common). While experimenting with a database across the internet I've noticed slow responses of the GUI, which motivated using threads to handle the back end. I'm playing with this now and considering a full app re-design to adequately tackle the issue. So I'm imagining to separate GUI (a class derived from QMainWindow) and back end stuff (a domain class, derived from QObject). This domain class looks like (I say so because I'm clearly not an authority on patterns - always learning) a facade pattern. The idea is to construct both objects in the main function and then pass a pointer of DomainClass to MainWindow, i.e. MainWindow(DomainClass *domain).
Then comes the very point of this question. I'm imaging to construct many (not so much actually) objects in the Domain an make them communicate via signal/slots mechanics. Like the following:
QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();
QThread* threadTM = new QThread;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);
m_tm->moveToThread(threadTM);
connect(threadTM, &QThread::started, m_tm, &TM::init);
threadTM->start();
But I'm getting the following:
QObject::connect: Cannot queue arguments of type 'QSqlDatabase'
(Make sure 'QSqlDatabase' is registered using qRegisterMetaType().)
I've noted that it works fine if I leave m_tm out of the thread. Like the following:
QThread* threadDB = new QThread;
m_database = new Database;
m_database->moveToThread(threadDB);
threadDB->start();
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnected);
Is this design reasonable? Which alternatives might be considered?
There are two issues. First, the runtime error tells you exactly what's wrong. You're trying to pass a database instance by value. Pass it by a pointer instead. The Qt metatype system knows how to handle such pointers.
class Database {
QSqlDatabase m_db;
...
public:
Q_SIGNAL void dbConnected(QSqlDatabase*);
...
};
Secondly, you can only use a QSqlDatabase instance from the thread it was created in (doc). So there's no point to passing it to an object living in a different thread. You should put TM in the same thread as that of the Database object, or you should have the Database object further encapsulate the database, exposing only a signal-slot interface that can then be used from any thread by using thread-safe queued calls.
Finally, you shouldn't use a "one thread per object" pattern. You must be able to give a reason, supported by measurements, that it is useful/helpful. A proliferation of threads is a bad thing - you should never have more than you have cores.
I'm making this an answer to have more room, but it might be tough as a comment considering #Kuba Ober answer.
To solve the second issue (pointed by #Kuba Ober) may I move DomainClass entirely to another thread? Coding the following on the constructor:
QThread* thread = new QThread;
this->moveToThread(thread);
connect(thread, &QThread::started, this, &DomainClass::init);
thread->start();
and coding the following on init():
m_database = new Database;
m_tm = new TM;
connect(m_database, &Database::dbConnected, m_tm, &TM::onDbConnecte
In respect to #Kuba Ober comments...
Moved thread management job to domain's owner, so it does:
QThread *thread = new QThread;
domain->moveToThread(thread);
thread->start();
Changed Domain's constructor to do:
QTimer::singleShot(0, this, SLOT(init()));
Works pretty nice :)

QThread and QML Locking Up

I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.

Controlling a QObject working in another thread, bypassing event queue, freezes the GUI

I'm working with QThread and slots/signals mechanism; I know there's a lot of threads about this on the Web in general and here at SO in particular, but I still could not find a solution. Anyway, here is the context.
The piece of code I am trying to come up with is aimed at controlling though the GUI an eventually long process, hence the use of a QThread.
I have a window with two buttons, start and stop. My Window also has a QThread and Task, where the latter inherits from a QObject. I do want to be able to stop my task while it is running, and to prevent starting it again if start is clicked while it is already running.
Here is an excerpt of Task (which fakes the long process):
class Task: public QObject
{
public:
Task(): QObject(), stop_(true) {}
private slots:
void startTask()
{
stop_ = false;
run();
}
void stopTask()
{
stop_ = true;
}
void run() const
{
while ( ! stop_)
{
sleep(1);
}
}
bool stop_;
};
I made two connections between the buttons and the task in the constructor of my Window:
class Window: public QWidget
{
public:
Window()
{
// Instantiate buttons and put them in a layout.
// ...
connect(buttonStart_, SIGNAL(clicked()), &task_, SLOT(startTask()));
connect(buttonStop_, SIGNAL(clicked()), &task_, SLOT(stopTask()),
Qt::DirectConnection);
task_.moveToThread(&thread);
thread_.start();
}
private:
QPushButton buttonStart_;
QPushButton buttonStop_;
QThread thread_;
Task task_;
};
I used Qt::DirectConnection in the second connect() in order to "force" processing of my signal requesting to stop the task, as (as I understand) task_ needs to return from its work before processing events further (if I use the default connection, all my clicks are processed after my task is "done").
Here, the Qt::DirectConnection "bypasses" the event queue, and that way I can stop my task. But to be honest I don't know if that is the proper way to do it, or if it is a workaround (thus possibly the root of my problem).
Anyway, this works OK that way, but when I start playing with my buttons, the GUI gets eventually frozen, and that's my problem!
Any help is welcome; thanks for your time!
Using a DirectConnection means that the slots will be executed in the UI thread (while your task thread is still running). This is not what you want. The way to handle this is to use an event loop in your thread, by running with QThread::exec().
In order for your thread to be able to respond as you want, you will need to ensure that the thread is able to process incoming events. There are a few ways to deal with this. One would be to call QCoreApplication::processEvents() occasionally while your task is running. Another is to use a QTimer connected to a slot which performs some processing. The important thing is to make sure that the event loop in your thread can run.
The first thing you need to understand is which thread your signal/slot connections are being executed in.
The default behavior in this particular case is to use a Qt::QueuedConnection, which will put your signal event onto the receiving thread's event queue. In the case of a Qt::DirectConnection, the slot is executed in the thread of the object that emitted the signal.
Using a Qt::DirectConnection would only be safe in this instance if you put a mutex around your stop_ variable to prevent both threads from accessing it at the same time.

Resources