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

borrowable_ptr, a threadsave callback solution #1713

Open
wants to merge 1 commit into
base: 2.5
Choose a base branch
from

Conversation

daschuer
Copy link
Member

@daschuer daschuer commented Jun 16, 2018

A wrapper class to protect pointers owned by another entity, allowing
safe access to the referenced object across threads. This prevents the
object from being deleted by its owner while other threads are executing
functions on the referenced object, implemented mostly lock-free, except during
reset(), if the object is still in use.

Use cases are:

  • Implementing callbacks to objects with shorter lifetimes.
  • A safe replacement for Qt's direct connections, which must not be used across
    threads in such cases.

Unlike std::shared_ptr, the object is not deleted when the last
borrowed_ptr falls out of scope. Ownership and deletion are always managed
by the original owner (via borrowable_ptr).

If the borrowable_ptr falls out of scope while there are active borrowed_ptr
instances, the thread is suspended until all borrowed_ptr instances are deleted
and the reference count reaches zero.

Thread safety:

  • It is thread-safe to replace the object in borrowable_ptr.
  • The transition is not atomic: borrowed_ptr instances become null before pointing
    to the new object.

Usage:

	int i = 5;
	{
	    // Make i borrowable, owned by the stack
            auto borrowable = borrowable_ptr(&i);
	    {
	        // Borrow i, this can be borrowd across threads
                // borrowed_ptr is a strong reference that guranties the borrowed object is
                // valid unit the end of the scope
                borrowed_ptr borrowed1 = borrowable.borrow();
	        borrowed_ptr borrowed2 = borrowable.borrow();
	    } // borrowed objects are returned
	} // borrowable_ptr falls out of scope, suspended if a borrowed pointer is not returned

@daschuer daschuer changed the title Added use_counting_ptr a threadsave calback solution use_counting_ptr, a threadsave calback solution Jun 16, 2018
@Be-ing
Copy link
Contributor

Be-ing commented Jun 16, 2018

Could you explain what specific problem motivated you to start working on this? Does it solve a problem that came up in #1675?

@daschuer
Copy link
Member Author

I am experience rar crashes when shutting down Mixxx.I was never able to reproduce it under gdb, so I have never reported a bug. One idea is that this is caused by explicit direct connections across threads. Qt does not prevent to call a callback from an already deleted object, if there is a race between the callback call from one thread and the delete call from an other thread.
If we use this new use_counting_ptr, the deleting thread is locked until the callback has returned.

@daschuer
Copy link
Member Author

We use these direct connection for the engine thread COs

@daschuer
Copy link
Member Author

I cannot use this currently, because of pending #1700

@Be-ing Be-ing added the engine label Jun 19, 2018
@Be-ing
Copy link
Contributor

Be-ing commented Jun 19, 2018

Can we come back to this in a few weeks after the 2.2 feature freeze?

@daschuer
Copy link
Member Author

I like to have this included.

@Be-ing
Copy link
Contributor

Be-ing commented Jun 19, 2018

Why?

@daschuer
Copy link
Member Author

I actually waiting for a review of #1700 more urgently. Our control objects where becoming a bit messy, and I think it is a good idea to clean them up in small steps instead of one giant PR.
This one so should hopefully solve the pending shut down crashes, finally.

@Be-ing
Copy link
Contributor

Be-ing commented Jun 19, 2018

I'm not questioning that we should clean the code, but I don't think < 2 weeks until a feature freeze is a good time to be focusing on it unless it fixes an important bug.

@Be-ing Be-ing added this to the 2.3.0 milestone Jun 23, 2018
@daschuer
Copy link
Member Author

@rryan Do you want to have a look here?
I like to have this new pointer to wrap the m_pCreatorCO here:
https://github.com/mixxxdj/mixxx/blob/master/src/control/control.h#L164

@daschuer
Copy link
Member Author

@uklotzde do you have interest to wrap your head around this? I would like it to fix the a probably cause of the crash on close fix I experience some times.

@uklotzde
Copy link
Contributor

Honestly I still don't get the point by reading the code??

Couldn't this be implemented in a simpler and more comprehensible way? I'm not able to decide if this works correctly in all possible cases. My feeling is that we might try to cover a design flaw by mitigating it with just another half-baked and fairly complex solution.

I noticed that the implementation has some technical flaws, e.g. the constructors are inconsistent and behave unexpectedly when invoked with a nullptr.

I came to the conclusion that we should use asynchronous signal/slot messaging whenever possible. Why plain callbacks? Trying to work around Qt's foundation and patterns is one of the main problems in our code base. I'm just criticizing myself, because this is what I would've done when rewriting the multi-threaded analysis code now. But I won't rewrite it a second time in C++ ;)

The global track cache is a slightly different story. It's also far too complex, but since track objects appear as shared mutable state everywhere we didn't have a choice without rewriting large parts of the application.

@daschuer
Copy link
Member Author

Thank you for looking into it.

This pointer was my idea for solving a crash on shut down when this https://github.com/mixxxdj/mixxx/blob/master/src/control/control.h#L164 object is deleted while an other thread is just about to call callback.

I would love to use a Qt solution for it, but it has not. Direct connections have no safety net in QT and suffer basically the same issue.

My idea was to use this pointer type to workaround this limitation, in an almost look free way.
The idea was to use this new pointer, for a maybe unusual but working solution of minimal scope.

Do you have alternative ideas? Is there a chance to tun this into a simpler and more comprehensible solution? That would be great.

@uklotzde
Copy link
Contributor

Would you please include an example were this technique is applied? I need to see it in action. We need this anyway. Adding unused and untested code to the repository is discouraged ;)

@daschuer
Copy link
Member Author

daschuer commented Dec 23, 2018

I have started to use the new pointer here: https://github.com/mixxxdj/mixxx/blob/master/src/control/control.h#L164
But it is becoming a great mess, because it is copied and stored all over the Mixxx code base.
We need to fix that first.

Many instances can be replaced by ControlProxyLt #1717

@github-actions
Copy link

This PR is marked as stale because it has been open 90 days with no activity.

@github-actions github-actions bot added the stale Stale issues that haven't been updated for a long time. label Oct 20, 2020
@Be-ing Be-ing changed the base branch from master to main October 23, 2020 23:50
@ronso0 ronso0 marked this pull request as draft November 20, 2020 10:21
@ronso0 ronso0 changed the title use_counting_ptr, a threadsave calback solution use_counting_ptr, a threadsave callback solution Dec 12, 2021
@daschuer daschuer changed the base branch from main to 2.5 December 8, 2024 12:23
@daschuer daschuer changed the title use_counting_ptr, a threadsave callback solution borrowable_ptr, a threadsave callback solution Dec 8, 2024
@daschuer daschuer marked this pull request as ready for review December 8, 2024 12:30
@daschuer
Copy link
Member Author

daschuer commented Dec 8, 2024

I have implemented the original solution on top of std::shared_ptr

please have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants