简体   繁体   中英

How to send signal from Singleton thread to another thread (Not singleton)

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

  1. 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:
    1. it is simplier
    2. requires less code
    3. works with QObject without problems
  2. 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM