-
Notifications
You must be signed in to change notification settings - Fork 95
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
Clean up Comic class and its connections to QThread #202
base: develop
Are you sure you want to change the base?
Conversation
QObject::destroyed should work just fine.
There is now less code to read and mark with `override`.
Constructors of the derived classes call load(), so it should be final.
This change prevents leaking a QThread if Comic::process() returns early because of a call to Comic::invalidate(). Extract signal-slot connections between a Comic and a QThread into Comic::moveAndConnectToThread() to reduce code duplication. Remove always true (thread != nullptr) checks. Add a pure virtual Comic::process() slot to use the function pointer-based signal-slot connection syntax.
Mac and Windows builds have failed because the I'd like to unify the two extract_delegate.h files into one by adding Is this unification an acceptable/good idea? |
After some consideration, I am against merging this PR. This is not because of a quality problem of the new code itself, but because of issues with the comic threading code in general. To conclude: I usually am not a person who dislikes code cleanups or refactoring, but in this case I want the bad code to look as ugly as possible as a deterrent and a sign that deeper refactoring is needed. As much as a cleanup is needed for this, doing it without solving the deeper issues will only serve as spray-coating the rust and hiding the code smell. @luisangelsm , @vedgy we need to discuss what to do with the leakage fix that is the core intention of this PR |
If you believe that the code should be reimplemented, a warning comment can be added - perhaps to the new function
I think that a warning comment/documentation is far easier and more explicit than relying on and enforcing the code duplication, ugliness and hoping that it will speed up refactoring. The unification not only improves the code appearance, it also reduces the likelihood of future omissions - when a necessary signal-slot connection is made in one place, but not the others. |
Yes, a warning comment would certainly help in this case regardless of the state of the code cleanup. There is another reason why I am not keen on merging this in its current state - testing. The code cleanup touches several sections of the code unrelated to the leak in ComicController and even if the modifications seem safe there is a high risk of side effects, exposing of previously masked errors and the general amount of testing needed to approve this is very high as we need to verify the proper threading in all three binaries YACReader ships, on all platforms. I don't know what @luisangelsm opinion on this is but personally I would prefer merging the changes proposed in this PR as separate easily testable steps, i.e. one PR with minimal impact to fix the thread leak followed by some safe code cleanup. |
I think the fix itself is the most risky part of this pull request. All other changes practically obviously don't affect the application behavior. Saving on testing time is exactly why I prefer to bundle related code cleanups with code fixes. Usually as separate commits within a single pull request. This way everything can be tested in one step rather than separately. Another reason I avoid separate pull requests is conflicts. When everything is separate, either merge conflicts have to be resolved (which risks introducing a bug in a botched merge) or I have to wait for one pull request to be merged before creating another one (which is inconvenient in view of review times that are often quite long here). Admittedly, the fix is not in a separate commit here. I can split the fix into a separate commit or even into another pull request depending on @luisangelsm's preference. |
connect(this, errorOpening0, thread, &QThread::quit, Qt::QueuedConnection); | ||
connect(this, errorOpening1, thread, &QThread::quit, Qt::QueuedConnection); | ||
connect(this, &Comic::imagesLoaded, thread, &QThread::quit, Qt::QueuedConnection); | ||
connect(this, &Comic::invalidated, thread, &QThread::quit, Qt::QueuedConnection); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I was implementing this function, I thought that with the default connection type Qt::AutoConnection
, the actual connection type is determined statically inside the QObject::connect()
call. But after some debugging, reading Qt source code and rereading the documentation, I realized that this is a truly different connection type:
The connection type is determined when the signal is emitted.
Since both ComicController
classes connected to all signals using Qt::AutoConnection
, calling this function instead changes their behavior. If this change is undesirable, I can restore the use of Qt::AutoConnection
by passing one more argument to this function - qthreadQuitConnectionType
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't want Qt::QueuedConnection in the server side. Do you use YACReader for iOS? Are these changes tested with it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I don't use or test the server. I have noticed the leak fixed in this PR while looking at code patterns similar to the one fixed in #203 and comparing very similar Render
and ComicController*
connection code. Then decided to unify the code to prevent future accidental divergence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I see that there is no real leak in the current implementation as Server never calls Comic::invalidate()
. Though it might call it in the future and connecting to Comic::invalidated
still make sense.
So it turns out that this pull request is pure code refactoring, not a fix.
If there is no real leak to be fixed here I personally would prefer to leave the code as it is. It is easy to introduce unwanted errors and hard to catch undefined behavior when working with QThread and the code is basically in maintenance mode already, so there is very little risk of future accidental divergence. Again, this is just my opinion, but I am actually for future divergence in the code. In its current state it is a dead end and the best way forward is to extract and refactor the core functionality to a new structure to which the different parts of the YACReader suite can then be ported step by step while keeping the old structure as a fallback as long as it is needed. |
One more thing. If we merge this the connection instructions for the slots and signals will no longer happen on the main thread but on the comic thread. That is a major change from the current behavior and it goes beyond the scope of a simple code cleanup. |
Why? A simple function call cannot magically be transferred to another thread.
Apart from the thread ping pong and the So an alternative to rewriting One more potential Server issue I just noticed: |
https://doc.qt.io/qt-5/qobject.html#moveToThread Sorry, but I don't have the time for a lengthy discussion on this. This is more than a cosmetic code change and I'd rather spend my time on getting actual work done instead of defending my decisions on this matter because you expect me to back up every choice I make with a quote. I have better things to do. |
Either I misunderstand your statement or you are mistaken. The |
6ccfc51
to
63fcde8
Compare
See the commit messages for details.