Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep InitExecutor in main gui thread #434

Merged
merged 1 commit into from
Sep 28, 2021

Conversation

promag
Copy link
Contributor

@promag promag commented Sep 26, 2021

The InitExecutor constructor moves the instance to a dedicated thread. This PR changes that by using GUIUtil::ObjectInvoke to run the relevant code in that thread.

A possible follow-up is to ditch the dedicated thread and use QThreadPool or even QtConcurrent::run (if we want to enable that).

@promag
Copy link
Contributor Author

promag commented Sep 27, 2021

Best reviewed without whitespace changes.

@hebasto
Copy link
Member

hebasto commented Sep 27, 2021

Why do you want to keep an instance of the InitExecutor in the GUI thread?

@promag
Copy link
Contributor Author

promag commented Sep 27, 2021

  • moveToThread is usually not called within the object;
  • we don't need to hold on to the thread, we just need to call initialize and shutdown asynchronously, so we could also improve that;
  • in QML it's not possible to connect/bind to objects in other threads, see Expose init executor instance gui-qml#37;

@hebasto
Copy link
Member

hebasto commented Sep 27, 2021

Concept ACK.

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach ACK 45b1c77, tested on Linux Mint 20.2 (Qt 5.12.8):

$ src/qt/bitcoin-qt -signet -printtoconsole -debug=qt
...
2021-09-27T11:15:47Z [main] GUI: requestInitialize : Requesting initialize
2021-09-27T11:15:47Z [qt-init] GUI: operator() : Running initialization in thread
...
2021-09-27T11:15:50Z [main] GUI: requestShutdown : Requesting shutdown
2021-09-27T11:15:50Z [qt-init] GUI: operator() : Running Shutdown in thread
...
2021-09-27T11:15:51Z [shutoff] Shutdown: done
2021-09-27T11:15:51Z [shutoff] GUI: operator() : Shutdown finished
2021-09-27T11:15:51Z [main] GUI: ~InitExecutor : Stopping thread
2021-09-27T11:15:51Z [main] GUI: ~InitExecutor : Stopped thread

@@ -9,7 +9,6 @@
#include <interfaces/init.h>
#include <interfaces/node.h>
#include <qt/bitcoin.h>
#include <qt/initexecutor.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I cannot imagine the reason how it slipped in #381 🤷‍♂️

@promag promag force-pushed the 2021-09-qt-initexecutor branch from 45b1c77 to 14acd74 Compare September 27, 2021 11:39
@hebasto
Copy link
Member

hebasto commented Sep 27, 2021

Sorry, I meant dropping __func__ part only, while keeping debugging messages that seem useful (at least for me).

@promag promag force-pushed the 2021-09-qt-initexecutor branch from 14acd74 to 03a5fe0 Compare September 27, 2021 12:06
@promag
Copy link
Contributor Author

promag commented Sep 27, 2021

No worries, done!

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 03a5fe0, tested on Linux Mint 20.2 (Qt 5.12.8).

The last lines in the log:

...
2021-09-27T14:14:55Z [shutoff] Shutdown: done
2021-09-27T14:14:55Z [shutoff] GUI: Shutdown finished
2021-09-27T14:14:55Z [main] GUI: ~InitExecutor : Stopping thread
2021-09-27T14:14:55Z [main] GUI: ~InitExecutor : Stopped thread

@promag
Copy link
Contributor Author

promag commented Sep 28, 2021

Code review ACK :trollface:

Copy link
Member

@jarolrod jarolrod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 03a5fe0

I've tested this and have reviewed the code. Keeping a QObject that will serve as a marker into a thread is a good design decision going forward.

@hebasto hebasto merged commit f000cdc into bitcoin-core:master Sep 28, 2021
@promag promag deleted the 2021-09-qt-initexecutor branch September 28, 2021 20:27
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Sep 28, 2021
@ryanofsky
Copy link
Contributor

ryanofsky commented Sep 29, 2021

Code review ACK 03a5fe0. Having InitExecutor associated with the GUI thread seems to be necessary in order to be able to write Connections { target: initExecutor ... } in QML.

But this seems like an overly complicated design because now instead of InitExecutor just being an QObject/QThread couple it is QObject/QThread/nested QObject throuple with two QObjects (this and this->m_context) each QObject connected to different thread.

It seems like a mistake here is letting QML code be aware of the InitExecutor object at all. Probably QML could should just be sending / receiving init events to and from a node or application object. QML code should not care about how init code executes or whether or not there is an executor. QML code should just be saying "hey bitcoin application, please start initializing and send the initialization result to this place", not "hey bitcoin application, give me your init executor, and init exector, please start initializing and send the result to this place".

@promag
Copy link
Contributor Author

promag commented Sep 29, 2021

@ryanofsky thanks for taking a look.

But this seems like an overly complicated design because now instead of InitExecutor just being an QObject/QThread couple it is QObject/QThread/nested QObject throuple with two QObjects (this and this->m_context) each QObject connected to different thread.

Implementation can change - how it runs async code. Personally, I don't think holding the thread makes sense, it's not used while the app runs.

It seems like a mistake here is letting QML code be aware of the InitExecutor object at all. Probably QML could should just be sending / receiving init events to and from a node or application object. QML code should not care about how init code executes or whether or not there is an executor. QML code should just be saying "hey bitcoin application, please start initializing and send the initialization result to this place", not "hey bitcoin application, give me your init executor, and init exector, please start initializing and send the result to this place".

We need one or some objects to bind to but I don't think the application is the best candidate. We could have some fat object with all properties and signals and just expose it. Later we could split that fat object into multiple objects and expose them.

In fact, QML allows different approaches. What you and @hebasto suggest seems to be https://doc.qt.io/archives/qt-5.9/qtqml-cppintegration-contextproperties.html. On the other hand, I'd prefer to follow https://doc.qt.io/archives/qt-5.9/qtqml-cppintegration-definetypes.html.

Following the example you mention, I was thinking something like:

InitExecutor {
    id: executor
}

Loader {
    active: executor.ready
    sourceComponent: MySuperInterface {
    }
}

Button {
    text: "start"
    onClicked: executor.initialize()
}

This seems preferable for multiple reasons:

  • no dependencies from context variables or the application
  • stuff is constructed when needed, with property bindings to/from relevant places
  • simplifies testing because it could mock InitExecutor

I don't think this violates any principle. In this case, we still have the init/shutdown logic implemented in C++ and the UI in QML.

But I'm fine with any approach, I'm just expressing my preference. Regardless of how we structure the work in QML, I think InitExecutor still needs to be improved.

@hebasto
Copy link
Member

hebasto commented Oct 2, 2021

I've linked to this discussion from bitcoin-core/gui-qml#37, and suggesting to continue it there.

delta1 added a commit to delta1/elements that referenced this pull request Apr 26, 2023
@bitcoin-core bitcoin-core locked and limited conversation to collaborators Aug 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants