why signal/slot not working with multiple threads? - multithreading

class A : public QObject{
Q_OBJECT
signals:
void a_sig();
public:
A(){ }
public slots:
void begin(){
QObject::connect(&_timer, SIGNAL(timeout()), this, SIGNAL(a_sig()));
_timer.start(1000);
}
private:
QTimer _timer;
};
class B : public QObject{
Q_OBJECT
public:
B(){ value = 0; }
public slots:
void b_slot(){
++value;
QFile file("out.txt");
file.open(QIODevice::WriteOnly);
QTextStream out(&file);
out << value << "\n";
file.close();
}
private:
int value;
};
int main(int argc, char **argv){
QCoreApplication app(argc, argv);
A a;
B b;
QThread aThread;
QThread bThread;
QObject::connect(&aThread, SIGNAL(started()), &a, SLOT(begin()));
QObject::connect(&a, SIGNAL(a_sig()), &b, SLOT(b_slot()));
a.moveToThread(&aThread);
b.moveToThread(&bThread);
aThread.start();
bThread.start();
return app.exec();
}
I'm trying to understand why b_slot() isn't getting called. Can anyone explain what's happening, and why b_slot() isn't getting called?

The problem is the ownership of the _timer member of the A class.
Since you're not explicitly initializing it, it is initialized without a parent object. So the a.moveToThread(&aThread) isn't moving the timer to aThread, and things get confused after that.
Change A's constructor to:
A() : _timer(this) {}
and your b_slot() will get called.

The problem is that while object a is moved to aThread, _timer object still belongs to the original main thread. Try initializing _timer inside begin method like that:
void begin() {
_timer = new QTimer;
QObject::connect(_timer, SIGNAL(timeout()), this, SIGNAL(a_sig()));
_timer->start(1000);
}
private:
QTimer *_timer;

Related

Run multiple threads and wait all to finish

I have the Emitter class that emulates a heavy process.
class Emitter : public QObject
{
Q_OBJECT
public:
explicit Emitter(QObject* parent = nullptr);
~Emitter();
int start();
signals:
void finished(int id);
private slots:
void heavyProcess();
private:
static int globalId;
int id;
QThread t;
void finish();
};
int Emitter::globalId = 1;
Emitter::Emitter(QObject* parent)
: QObject{ parent }
, id{ globalId++ }
{
moveToThread(&t);
t.start();
}
Emitter::~Emitter()
{
qDebug() << "Destruct" << id;
t.quit();
t.wait();
}
int
Emitter::start()
{
QMetaObject::invokeMethod(this, "heavyProcess");
return id;
}
void
Emitter::heavyProcess()
{
auto time{ QRandomGenerator::global()->bounded(1000u, 3000u) };
qDebug() << "Id" << id << "Time" << time;
QThread::msleep(time);
finish();
}
void
Emitter::finish()
{
qDebug() << "Finished" << id;
emit finished(id);
}
Also, there is a manager that creates two instances of the Emitter class. I want to run the heavy process of each instance and when all the instances finishes, the manager emits a finished signal.
class Manager : public QObject
{
Q_OBJECT
public:
explicit Manager(QObject* parent = nullptr);
void start();
signals:
void finished();
public slots:
private slots:
void update(int id);
private:
QHash<int, QSharedPointer<Emitter>> emitters;
};
Manager::Manager(QObject* parent)
: QObject{ parent }
{}
void
Manager::start()
{
QSharedPointer<Emitter> em1{ new Emitter{} };
QSharedPointer<Emitter> em2{ new Emitter{} };
connect(em1.get(), &Emitter::finished, this, &Manager::update);
connect(em2.get(), &Emitter::finished, this, &Manager::update);
emitters.insert(em1->start(), em1);
emitters.insert(em2->start(), em2);
}
void
Manager::update(int id)
{
qDebug() << "update" << id;
emitters.remove(id);
if (emitters.isEmpty()) {
qDebug() << "Empty";
emit finished();
}
}
In the main function I expect to quit the QCoreApplication after the Manager emits its finished signal.
int
main(int argc, char* argv[])
{
QCoreApplication a(argc, argv);
Manager manager;
QObject::connect(&manager, &Manager::finished, &a, &QCoreApplication::quit);
manager.start();
return a.exec();
}
Sometimes I have this output
Id 1 Time 1416
Id 2 Time 1096
Finished 2
update 2
Destruct 2
That means that one instance of the Emitter class is not finished, maybe because the thread is "killed" before it has time to finish their process.
My questions:
Is this a correct approach to create multiple threads to execute the same process with a different set of data?
Why the finished signal of the Manager is called while a thread is running?
If the way I am managing the threads is wrong, could you guide me to do in a better way?

Are we limited to 3300-3400 threads/process in 64-bit Windows system?

Following along Threaded Fortune Server Example I've created a similar server that receives json object from clients and it can handle around 3330 clients simultaneously without any issue.
If I increase the number of clients to 3400, I get:
CreateWindow() for QEventDispatcherWin32 internal window failed (The current process has used all of its system allowance of handles for Window Manager objects.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 1158, The current process has used all of its system allowance of handles for Window Manager objects.
How can I increase number of threads?
EDIT
Instead of FortuneThread I have ClientThread like this:
class ClientThread : public QThread
{
Q_OBJECT
public:
explicit ClientThread(qintptr socketDescriptor);
void run() override;
signals:
void readyRemove();
private:
qintptr socketDescriptor;
};
and in run() I am creating client:
void ClientThread::run()
{
Client c(socketDescriptor);
emit readyRemove();
}
and the Client is as usual:
class Client : public QTcpSocket
{
Q_OBJECT
public:
explicit Client(qintptr descriptor);
public slots:
void onReadyRead();
void onError(QTcpSocket::SocketError error);
};
and implemented as:
Client::Client(qintptr descriptor)
{
connect(this, &Client::readyRead, this, &Client::onReadyRead);
connect(this, static_cast<void (Client::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error), this, &Client::onError);
setSocketDescriptor(descriptor);
waitForDisconnected();
}
void Client::onReadyRead()
{
QVariantMap map = QJsonDocument::fromJson(readAll()).object().toVariantMap();
qDebug() << map["Name"].toString() << map["Age"].toInt();
}
void Client::onError(SocketError error)
{
if(state() == ConnectedState && error == SocketTimeoutError)
waitForDisconnected();
}
Ofcourse, onReadyRead() can be problematic in this way. Server class takes care of ClientThread. It stores each client thread in a QVector and removes it when disconnected from host and here is its header:
class Server : public QTcpServer
{
Q_OBJECT
public:
explicit Server(qint16 port, QObject *parent = 0);
~Server();
protected:
void incomingConnection(qintptr descriptor) override;
public slots:
void removeClient();
private:
QVector<ClientThread*> clients;
};
and incomingConnection and removeClient do these:
void Server::incomingConnection(qintptr descriptor)
{
ClientThread *thread = new ClientThread(descriptor);
connect(thread, &ClientThread::readyRemove, this, &Server::removeClient);
thread->start();
clients.push_back(thread);
}
void Server::removeClient()
{
ClientThread *thread = (ClientThread*)sender();
thread->quit();
thread->deleteLater();
clients.removeOne(thread);
}
To test the Server application I've used the following Console application:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QVector<QTcpSocket*> clients;
for(int i = 0; i < 3300; i++){
QTcpSocket *sock = new QTcpSocket();
sock->connectToHost("127.0.0.1", 2000);
sock->waitForConnected();
clients.push_back(sock);
}
QJsonObject obj;
obj["Name"] = QString("TestName");
obj["Age"] = 1;
QJsonDocument doc(obj);
foreach (QTcpSocket *s, clients) {
s->write(doc.toJson());
s->flush();
}
foreach (QTcpSocket *s, clients) {
s->close();
s->deleteLater();
}
}

How to connect signal from qconcurrent thread to gui thread sharing one string

I'm trying to update gui label with an other thread information (QString).
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public Q_SLOTS:
void sl_appendInfo(QString p_text);
private:
Ui::MainWindow *ui;
QFuture<void> m_thread;
QFuture<void> m_engine;
engine* m_object;
};
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
m_object = new engine();
qRegisterMetaType<QString>();
bool success = connect(this->m_object, SIGNAL(engine::sig_appendInfo(QString)), this, SLOT(sl_appendInfo(QString)), Qt::QueuedConnection);
if(!success)
{
qDebug("success failed");
}
m_engine = QtConcurrent::run(this->m_object, &engine::eventLoop);
}
//slot declaration in mainwindow.cpp
void MainWindow::sl_appendInfo(QString p_text)
{
ui->label->setText(p_text.toLocal8Bit().constData());
}
class engine : public QObject
{
Q_OBJECT
public:
engine();
~engine();
void eventLoop();
Q_SIGNALS:
void sig_exitengine(void);
void sig_appendInfo(QString p_text);
};
void engine::eventLoop()
{
int state = false;
while(true)
{
state = getNextEvent(m_event);
if (state == true)
{
sig_appendInfo("information for gui: we handled a new event !");
state=false;
}
QThread::msleep(1000);
}
}
Now I use this link : My signal / slot connection does not work to build my own code but it didn't work, the connection failed... Can I have some help please?
Thank you
Your connect syntax is wrong. You shouldn't include the class name in the SIGNAL macro. If you use the old syntax, it should be:
bool success = connect(m_object, SIGNAL(sig_appendInfo(QString)), this, SLOT(sl_appendInfo(QString)), Qt::QueuedConnection);
Or if you want to use the new syntax:
bool success = connect(m_object, &engine::sig_appendInfo, this, &MainWindow::sl_appendInfo, Qt::QueuedConnection);

how to write connect statement of lineEdit in different class

How can I make signal and slot of lineEdit which is declare in another class ?
LineEdit is declared in Peakdetechtion class and i want to make signal and slot in peaksettingform so how can I do this?
the QLineEdit either has to be accessible from the outside (public or get) or you have to forward the signal you are interested in.
accessible version (incomplete and very dirty)
class Peakdetechtion { // horrible name
public:
QLineEdit* getLineEdit() { return m_lineEdit; } // don't do it
private:
QLineEdit* m_lineEdit;
};
class Peaksettingform : public QObject { //horrible name
Q_OBJECT
public:
Peaksettingform(Peakdetechtion *p, QObject *parent = 0)
: QObject(parent) {
// you can do this from outside and replace 'this' with a pointer to a Peaksettingform object
connect(p->getLineEdit(), SIGNAL(textChanged(const QString &)), this, SLOT(handleText(const QString &)));
}
public slots:
void handleText(const QString &);
};
signal forwarding
class Peakdetechtion : public QObject { // horrible name
Q_OBJECT
public:
Peakdetechtion() {
m_lineEdit = new QLineEdit(); // should have a parent but i am lazy
connect(m_lineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(leTextChanged(const QString&)));
}
signals:
void leTextChanged(const QString &);
private:
QLineEdit* m_lineEdit;
};
class Peaksettingform : public QObject { //horrible name
Q_OBJECT
public:
Peaksettingform(Peakdetechtion *p, QObject *parent = 0)
: QObject(parent) {
// you can do this from outside and replace 'this' with a pointer to a Peaksettingform object
connect(p, SIGNAL(leTextChanged(const QString &)), this, SLOT(handleText(const QString &)));
}
public slots:
void handleText(const QString &);
};

error C2664 cannot convert parameter 1 from 'std::string (__thiscall ClassName::* )(std::string)' to 'std::string (__cdecl *)(std::string)

I'm making a unmanaged application to handle an event fired in c# here.
FYI:: I want to handle a custom event when my Name property in C# class is changed.
I have gone through the following links:
Explanation about passing pointer to member function as parameter
Something similar to my problem.But couldn't understand the solution
Now,
In NativeApp.cpp,I have a member function which is passed as a function pointer as parameter in a method present in the c++/CLI wrapper
//NativeApp.cpp
std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
void Class1::NativeMethod()
{
UnmanagedWrapperClass* unmanagedWrapperClass=new UnmanagedWrapperClass();
unmanagedWrapperClass->WrapperMethod(&Class1::FunctionToBePointed,"Hello")
}
In Wrapper.h,
//Wrapper.h
class __declspec(dllexport) UnmanagedWrapperClass
{
boost::signals2::signal<void(std::string)>signalEvent;
void WrapperMethod(std::string (*GetCallBack)(std::string),std::string value);
}
When I call the WrapperMethod from NativeApp.cpp,
I subscribe my EventHandlerWrapper to a c# event
connect the function pointer to my boost signal signalEvent.
Set the Name property of the CSharp Class
When the Name Property is set, c# event is fired, EventHandlerWrapper method in Wrapper.cpp is executed.Looks like this::
void EventHandlerWrapper(string value)
{
if(signalEvent.connected())
{
signalEvent(value);
}
For some reasons I can't make my FunctionToBePointed(std::string) method as a non-member function.
P.S:: All ears for any other design approach.
In your real use-case can you simply make FunctionToBePointed a static method?
static std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
If yes your code should work.
The reason is that instance methods are implicitly called with an hidden this pointer, this is the thiscall calling convention, whereas static methods simply use the cdecl convention because they don't work on any instance.
EDIT:
A sample with Boost::bind:
The MyClass C# class:
using System;
using System.ComponentModel;
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate{};
private string name;
public string Name
{
get
{
return name;
}
set
{
if (name != value)
{
name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
The C++/CLI wrapper:
Wrapper.h:
class WrapperPrivateStuff;
class __declspec(dllexport) UnmanagedWrapperClass
{
private: WrapperPrivateStuff* _private;
public: void changeIt(std::string newName);
public: void WrapperMethod(boost::function<std::string(std::string)> GetCallBack);
public: UnmanagedWrapperClass();
};
Wrapper.cpp:
#using "MyClass.dll"
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include "Wrapper.h"
#include <msclr\auto_gcroot.h>
#include <msclr\marshal_cppstd.h>
#include <msclr\event.h>
class WrapperPrivateStuff
{
public: boost::signals2::signal<void(std::string)>signalEvent;
public: msclr::auto_gcroot<MyClass^> a;
public: void EventHandlerWrapper(System::Object^, System::ComponentModel::PropertyChangedEventArgs^ args)
{
this->signalEvent(msclr::interop::marshal_as<std::string>(a->Name));
}
public: WrapperPrivateStuff()
{
a = gcnew MyClass();
a->PropertyChanged += MAKE_DELEGATE(System::ComponentModel::PropertyChangedEventHandler, EventHandlerWrapper);
}
BEGIN_DELEGATE_MAP(WrapperPrivateStuff)
EVENT_DELEGATE_ENTRY(EventHandlerWrapper, System::Object^, System::ComponentModel::PropertyChangedEventArgs^)
END_DELEGATE_MAP()
};
void UnmanagedWrapperClass::changeIt(std::string newName)
{
this->_private->a->Name = msclr::interop::marshal_as<System::String^>(newName);
}
UnmanagedWrapperClass::UnmanagedWrapperClass()
{
this->_private = new WrapperPrivateStuff();
}
void UnmanagedWrapperClass::WrapperMethod(boost::function<std::string(std::string)> GetCallBack)
{
_private->signalEvent.connect(GetCallBack);
}
And the native application, test.cpp:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include "Wrapper.h"
class Class1
{
private: std::string name;
public: Class1(std::string name)
: name(name)
{
}
public: std::string FunctionToBePointed(std::string msg)
{
std::cout << "Hey it's " << name << "! Got: " << msg << std::endl;
return msg;
}
};
int main(void)
{
UnmanagedWrapperClass wrapper;
Class1 class1("Ed");
wrapper.WrapperMethod(boost::bind(&Class1::FunctionToBePointed, &class1, _1));
wrapper.changeIt("azerty");
return 0;
}
Result:
>test.exe
Hey it's Ed! Got: azerty
I have a more generic solution but it is really ugly. :(
Let me know if this fix your issue...

Resources