tetsurom / rxqt

The Reactive Extensions for Qt.
MIT License
187 stars 30 forks source link

Using the rxqt::run_loop in a large code base #28

Open michalfapso opened 3 years ago

michalfapso commented 3 years ago

Hi Tetsuro. Thanks for this library.

What is the preferred way to use the rxqt::run_loop in a larger codebase with a lot of classes?

As all qt gui related methods have to be run in the main (gui) thread, in all such cases, I need to add .observe_on(main_thread) before each .subscribe(...). I saw your example https://github.com/tetsurom/rxqt/blob/master/sample/thread/main.cpp, but when the code is spread among multiple source files, these options come to my mind:

  1. Encapsulate the rxqt::run_loop in a singleton and initialize it after QApplication
  2. Create the rxqt::run_loop after QApplication, and then put just the result of rxqt_run_loop.observe_on_run_loop() into a singleton.
  3. Before each place where I'd like to use .observe_on(main_thread), I'd put
    rxqt::run_loop rxqt_run_loop;
    auto main_thread = rxqt_run_loop.observe_on_run_loop();

    Are these approaches equivalent in functionality? The 2. option would lead to the least code bloat. What would you prefer?

Thanks for any hints. Michal

michalfapso commented 3 years ago

The singleton approach could look like this:

foo.cpp where we need to subscribe on the gui thread:

#include "rxqt_gui_thread.h"
#include <cassert>
...
some_request
.observe_on(RxqtGuiThread::GetInstance().Get()) // <-- This is the important part
.subscribe([](auto){
    assert(qApp->thread() == QThread::currentThread());
});
...

main.cpp:

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    RxqtGuiThread::GetInstance(); // Initialization must happen in the gui thread
    ...
}

rxqt_gui_thread.h:

#ifndef RXQTGUITHREAD_H
#define RXQTGUITHREAD_H

#include "singleton.h"
#include "rxcpp/rx.hpp"
#include "rxqt.hpp"
#include <QCoreApplication>
#include <cassert>

namespace detail {
class RxqtGuiThread
{
    public:
        RxqtGuiThread()
            : mLoop()
            , mWorker(mLoop.observe_on_run_loop())
        {
            assert(qApp->thread() == QThread::currentThread());
        }

        rxcpp::observe_on_one_worker Get() const { return mWorker; }
    private:
        rxqt::run_loop mLoop;
        rxcpp::observe_on_one_worker mWorker;
};
}

typedef Singleton<detail::RxqtGuiThread> RxqtGuiThread;

#endif // RXQTGUITHREAD_H

singleton.h (just for completeness):

#ifndef SINGLETON_H
#define SINGLETON_H

template <class T>
class Singleton
{
    public:
        static T& GetInstance()
        {
            static T instance;
            return instance;
        }
    private:
        Singleton();                      // Don't implement
        Singleton(Singleton const&);      // Don't Implement
        void operator=(Singleton const&); // Don't implement
};

#endif // SINGLETON_H

It seems to work well :)