I'm facing a problem while creating a Singleton class with it's own thread that sends signal to another thread which is not a singleton class.
Consumer.h
class Consumer : public QThread
{
Q_OBJECT
public:
explicit Consumer(QObject *parent = 0);
Consumer(Worker *Worker);
signals:
void toMessage(const bool& keepCycle);
public slots:
void getMessage(const QString& str);
private:
int m_counter;
};
Consumer.cpp
Consumer::Consumer(QObject *parent) :
QThread(parent)
{
m_counter = 0;
connect(Worker::Instance(), SIGNAL(sendMessage(QString)), this, SLOT(getMessage(QString)));
connect(this, SIGNAL(toMessage(bool)), Worker::Instance(), SLOT(fromMessage(bool)));
}
// Get's message from Singleton thread if counter > 5 sends signal to terminate cycle in Singleton thread
void Consumer::getMessage(const QString &str)
{
m_counter++;
if(m_counter <= 5) {
qDebug() << "Got message " << m_counter << ": " << str << "\n";
return;
}
else {
emit toMessage(false);
}
}
Singleton is done as follows (suspect it's Not Thread-safe):
template <class T>
class Singleton
{
public:
static T* Instance()
{
if(!m_Instance) m_Instance = new T;
assert(m_Instance != NULL);
return m_Instance;
}
protected:
Singleton();
~Singleton();
private:
Singleton(Singleton const&);
Singleton& operator=(Singleton const&);
static T* m_Instance;
};
template <class T> T* Singleton<T>::m_Instance = NULL;
And Worker Singleton class
class Worker : public QThread
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
void run();
signals:
void sendMessage(const QString& str);
public slots:
void fromMessage(const bool& keepCycle);
private:
volatile bool m_keepCycle;
};
typedef Singleton<Worker> Worker;
Worker.cpp
Worker::Worker(QObject *parent) :
QThread(parent)
{
m_keepCycle = true;
}
void Worker::run()
{
while(true) {
if(m_keepCycle) {
QString str = "What's up?";
ElWorker::Instance()->sendMessage(str);
}
else {
qDebug() << "Keep Alive" << false;
break;
}
}
qDebug() << "Value of keepCycle" << m_keepCycle;
}
void Worker::fromMessage(const bool &keepCycle)
{
m_keepCycle = keepCycle;
qDebug() << "\nMessage FROM: " << keepCycle << "\n";
}
The main.cpp
Consumer consumer;
ElWorker::Instance()->start();
consumer.start();
Can you help me to create thread-safe Singleton and to send signals between threads?
First of all, it is highly recommended to separate worker from it's thread:
class Object : public QObject
{
...
public slots:
void onStarted(); // if needed
void onFinished(); // if needed
...
};
...
mObject = QSharedPointer < Object >(new Object);
mThread = new QThread(this);
mObject->moveToThread(mThread);
connect(mThread, SIGNAL(started()), mObject, SLOT(onStarted())); // if needed
connect(mThread, SIGNAL(finished()), mObject, SLOT(onFinished())); // if needed
mThread->start();
Second of all, there are a lot of ways of creating a singleton. My favourite is this:
Object * obj(QObject *parent = 0)
{
static Object *mObj = new Object(parent);
return mObj;
}
...
obj(this); // creating
obj()->doStuff(); // using
Now, about thread-safety. Sending signals is thread-safe, unless you're sending pointers or non-constant references. Which, according to your code, you are not. So, you should be fine.
UPDATE
Actually, I didn't get how created thread-safe singleton above and I'm
sending a signal from Worker TO Consumer Not a Thread itself? – hiken
Static values inside of function are created and initialized only once, so the first time you call obj function mObj is created and returned and each other time you call it, previously created mObj is returned. Also, I didn't say, it's thread-safe, all I said - I like this way better, then template one, because:
it is simplier
requires less code
works with QObject without problems
Yes, you should send signals from worker class, not thread one. Qt's help has a good example (the first one, not the second one): http://doc.qt.io/qt-5/qthread.html#details. The only thing QThread should be used for - is controlling thread's flow. There are some situations, when you need to derive from QThread and rewrite QThread::run, but your case isn't one of them.
Related
I would like to assign a name to a thread, the thread itself must do this. The thread is a class member of the class foo.
I would like to start this thread with a lambda but unfortunately I get the error message:
no match for call to '(std::thread) (foo::start()::<lambda()>)
Can someone explain to me where the problem is?
Previously I had created a temporary thread object, and put this with move on the thread "manage", however, I can then give no name.
class foo {
public:
int start()
{
this->manage([this](){
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage"); // Give thread an human readable name (non portable!)
while(1){
printf("do work");
}
});
return 1;
}
private:
int retVal;
std::thread manage;
};
You passed the lambda in a wrong way, after initialization the manage thread can't be initialized again. you should create a new std::thread and assign it.
the following compiles and indeed prints "manage".
class foo {
public:
int start()
{
manage = std::thread([this]{
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage");
char name[16];
pthread_getname_np(pthread_self(), &name[0], sizeof(name));
cout << name << endl;
});
manage.join();
return 1;
}
private:
int retVal;
std::thread manage;
};
Now I want to create a thread and put in my class "AVC_file" inatance.
But when I print currentThreadId in textBroswer, I found MainWindows's threadID is same with the thread I created. show pitures like below.
Framework::Framework(QWidget * parent) : QMainWindow(parent)
{
ui.setupUi(this);
int threadID = (int)QThread::currentThreadId();
ui.textBrowser->append("Main Tread ID : " + QString::number(threadID));
}
void Framework::on_OpenAVCFile_clicked()
{
QString filePath = QFileDialog::getOpenFileName(
this, tr("Open File"), "C:\\", "AVC File (*.avc)"
);
if (!filePath.isEmpty())
{
QMessageBox::information(this, tr("File Name"), filePath);
}
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "info", file.errorString());
}
else {
QThread *thread = new QThread(this);
int threadID = (int)thread->currentThreadId();
ui.textBrowser->append("Second Tread ID : " + QString::number(threadID) + "\n");
AVC_File *AVC_file = new AVC_File();
AVC_file->moveToThread(thread);
connect(AVC_file, SIGNAL(requestFileContent(QString)), this, SLOT(addFileContent(QString)));
connect(AVC_file, SIGNAL(requestFileDebug(QString)), this, SLOT(addFileDebug(QString)));
connect(AVC_file, SIGNAL(requestFileCorrectness(bool, int)), this, SLOT(adddFileCorrectness(bool, int)));
connect(AVC_file, SIGNAL(requestNewValue(unsigned int, int)), this, SLOT(addNewValue(unsigned int, int)));
thread->start();
AVC_file->AVC_FileCheck(file);
}
}
Images about my code and results-->
Main Windows, create thread and results
Oh!I also try emit info in my "AVC_file" instance?like below.
void AVC_File::AVC_FileCheck(QFile &file)
{
int threadID = (int)QThread::currentThreadId();
emit requestFileContent("Thread ID by emit" + QString::number(threadID) + "\n");
QTextStream in(&file);
........
........
}
Emit threadID info
Anyone can help me?
BTW, I use visual studio Qt add-in to develop this project.
QThread::currentThreadId() is a static method.
When you call it, it returns the thread ID of the thread that executes it.
In both your cases that's the main thread.
There are several issues that I'll address in random order.
First of all, using thread IDs is bad user experience. Give the threads a descriptive name:
int main(...) {
QApplication app(...);
QThread myThread;
MyObject myObject;
myObject->moveToThread(&myThread);
QThread::currentThread()->setObjectName("mainThread");
myThread.setObjectName("myThread");
...
}
Then use QThread::currentThread()->objectName() to retrieve it. You can also pass QObject* to qDebug() to display the name of the thread:
qDebug() << QThread::currentThread();
Your signal invocation would then become:
QString currentThreadName() {
return QThread::currentThread()->objectName().isEmpty() ?
QStringLiteral("0x%1").arg(QThread::currentThread(), 0, 16) :
QThread::currentThread()->objectName();
}
...
emit requestFileContent(
QStringLiteral("Emitting from thread \"%1\"\n").arg(currentThreadName));
Then, use the above to deal with the thread you've created:
auto thread = new QThread(this);
thread->setObjectName("fileThread");
ui.textBrowser->append(QStringLiteral("Worker thread: \"%1\").arg(thread->objectName()));
auto AVC_file = new AVC_File;
AVC_file->moveToThread(thread);
...
But AVC_FileCheck is invoked from the main thread. Whether that's OK or not depends on how that method is implemented. It needs to be thread-safe, see this question for a discussion of that. TL;DR: The following pattern could be a starting point:
class AVC_file : public QObject {
Q_OBJECT
Q_SLOT void fileCheck_impl(QIODevice * dev) {
dev->setParent(this);
...
}
Q_SIGNAL void fileCheck_signal(QIODevice *);
public:
void fileCheck(QIODevice *dev) { fileCheck_signal(dev); }
AVC_file(QObject *parent = nullptr) : QObject(parent) {
connect(this, &AVC_file::fileCheck_signal, this, &AVC_file::fileCheck_impl);
...
}
};
Finally, your existing AVC_fileCheck API is broken. You pass QFile by reference: this won't ever work since it ceases to exist as soon as on_OpenAVCFile_clicked returns. When AVC_file uses that file in its thread, it's a dangling object reference.
Instead, you must pass the ownership of the file to AVC_file, and pass a pointer to an instance that AVC_file will dispose when done with. Or simply let AVC_file open the file for you!
I have an object MainWorker ran as a separate thread thanks to moveToThread method.
MainWorker has a member SubWorker which is also ran as a separate thread. Both threads are working in infinite loops.
The idea is, MainWorker and SubWorker both perform some separate computations. Whenever SubWorker is done computing, it should notify MainWorker with the result.
Therefore I intuitively made first connection between signal emitted by SubWorker and a slot of MainWorker, but it wasn't working, so I made two more connections to rule out some potential problems:
connect(subWorker, &SubWorker::stuffDid, this, &MainWorker::reportStuff)); //1
connect(subWorker, &SubWorker::stuffDid, subWorker, &SubWorker::reportStuff); //2
connect(this, &MainWorker::stuffDid, this, &MainWorker::reportStuffSelf); //3
It seems, that what is not working is exactly what I need - cross thread communication, because connection 2 and 3 works as expected. My question is: How do I make connection 1 work?
Edit: Apparently, after Karsten's explanation, it is clear that infinite loop blocks the EventLoop. So the new question is, how can I send messages (signals, whatever) from an infinite loop thread to its parent thread?
I am new to Qt, there is a high chance that I got it completely wrong. Here goes the minimal (not)working example:
MainWorker.h
class MainWorker : public QObject
{
Q_OBJECT
public:
MainWorker() : run(false) {}
void doStuff()
{
subWorker = new SubWorker;
subWorkerThread = new QThread;
subWorker->moveToThread(subWorkerThread);
connect(subWorkerThread, &QThread::started, subWorker, &SubWorker::doStuff);
if(!connect(subWorker, &SubWorker::stuffDid, this, &MainWorker::reportStuff)) qDebug() << "connect failed";
connect(subWorker, &SubWorker::stuffDid, subWorker, &SubWorker::reportStuff);
connect(this, &MainWorker::stuffDid, this, &MainWorker::reportStuffSelf);
subWorkerThread->start();
run = true;
while(run)
{
QThread::currentThread()->msleep(200);
emit stuffDid();
}
}
private:
bool run;
QThread* subWorkerThread;
SubWorker* subWorker;
signals:
void stuffDid();
public slots:
void reportStuff()
{
qDebug() << "MainWorker: SubWorker did stuff";
}
void reportStuffSelf()
{
qDebug() << "MainWorker: MainWorker did stuff (EventLoop is not blocked)";
}
};
SubWorker.h
class SubWorker : public QObject
{
Q_OBJECT
public:
SubWorker() : run(false) {}
void doStuff()
{
run = true;
while(run)
{
qDebug() << "SubWorker: Doing stuff...";
QThread::currentThread()->msleep(1000);
emit stuffDid();
}
}
private:
bool run;
public slots:
void reportStuff()
{
qDebug() << "SubWorker: SubWorker did stuff";
}
signals:
void stuffDid();
};
main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MainWorker *mainWorker = new MainWorker;
QThread *mainWorkerThread = new QThread;
mainWorker->moveToThread(mainWorkerThread);
QObject::connect(mainWorkerThread, &QThread::started, mainWorker, &MainWorker::doStuff);
mainWorkerThread->start();
return a.exec();
}
I need to call a web request cyclically, so, the easy way to do that is, of course, create a thread and call my request followed by a sleep..
The issue is that I wrote my code and it basically works. When I try to call the get inside a QThread, I don't receive any result, the event associated to the response is never invoked:
class RemoteControl : public QObject {
Q_OBJECT
QNetworkAccessManager* manager;
public:
explicit RemoteControl(QObject* parent = 0);
~RemoteControl() {}
public slots:
void process() {
std::cout << "start" << std::endl;
while (true) {
execute();
std::cout << "called" << std::endl;
sleep(5);
}
}
void execute() {
QUrl url("my request for num of visitors that works..");
QNetworkRequest req;
req.setUrl(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
QNetworkReply* reply = manager->get(req);
}
void downloadFinished(QNetworkReply* reply) {
std::cout << "finished called" << std::endl;
QByteArray resp = reply->readAll();
std::cout << resp.data() << std::endl;
}
signals:
void finished();
private:
WebRequest* WebReq_;
};
RemoteControl::RemoteControl(bool* enable, LoggerHandle* Log, QObject* parent) : QObject(parent)
{
enable_ = enable;
Log_ = Log;
running_ = false;
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(downloadFinished(QNetworkReply*)));
}
int main() {
//.... my code....
QThread* t3 = new QThread;
RemoteContr->moveToThread(t3);
QObject::connect(t3, SIGNAL(started()), RemoteContr, SLOT(process()));
t3->start();
//.... my code....
}
So, what happens is that using this code I didn't get any errors, in the output I can see start and called but never finished called..
it seems that the event downloadFinished is never called.
Can you help me to understand why?
Something wrong in my class RemoteControl?
Thanks
Andrea
You don't need a thread for this. The QNetworkAccessManager is asynchronous, so the calls you're using do not block. Instead of a thread, just do something like this in your main function:
QTimer * timer = new QTimer;
connect(timer, SIGNAL(timeout()), RemoteContr, SLOT(execute());
timer->start(5000); // = 5 seconds
Then, execute is invoked every 5 seconds, which seems to be what you want.
By the way, I think the reason you aren't getting results is that the while loop in process is blocking the thread. You can get rid of the process slot with this approach.
I tried yesterday to use std::thread correctly, but it's very dark for me.
My program implementation with pthread works well I don't have any problem with it. I would like to have the same solution with std::thread (if possible).
Solution with pthread:
void *MyShell(void *data) {
std::string str;
while(1) {
std::cin >> str;
std::cout << str << std::endl;
}
}
void mainloop() {
pthread_t thread;
pthread_create(&thread, NULL, aed::map::shell::Shell, this);
...
pthread_cancel(thread);
}
And now the solution which doesn't work everytime, with std::thread:
class ShellThreadInterrupFlag {
public:
void interrupt() {
throw std::string("Thread interruption test\n");
}
};
class ShellThread {
public:
template<typename FunctionType, typename ParamsType>
ShellThread(FunctionType f, ParamsType params) {
std::promise<ShellThreadInterrupFlag *> p[3];
_internal_thread = new std::thread(f, p, params);
_flag = p[0].get_future().get();
_internal_thread->detach();
p[1].set_value(_flag); // tell the thread that we detached it
p[2].get_future().get(); // wait until the thread validates the constructor could end (else p[3] is freed)
}
~ShellThread() {
delete _internal_thread;
}
void interrupt() {
_flag->interrupt();
}
private:
std::thread *_internal_thread;
ShellThreadInterrupFlag *_flag;
};
void Shell(std::promise<ShellThreadInterrupFlag *> promises[3],
aed::map::MapEditor *me)
{
ShellThreadInterrupFlag flag;
promises[0].set_value(&flag); // give the ShellThread instance the flag adress
promises[1].get_future().get(); // wait for detaching
promises[2].set_value(&flag); // tell ShellThread() it is able to finish
while(1) {
std::cin >> str;
std::cout << str << std::endl;
}
}
void mainloop()
{
ShellThread *shell_thread;
shell_thread = new ShellThread(Shell, this);
... // mainloop with opengl for drawing, events gestion etc...
shell_thread->interrupt();
}
Sometimes, when I launch the program, the std::cin >> str is called and the mainloop is blocked.
Does anyone know why the thread is blocking my mainloop ? And how could I avoid this problem ?