-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Fix async Python functors invoking from multiple C++ threads (#1587) #1595
Conversation
I'm a bit confused by the change, can you clarify? Specifically, I'm wondering if/why it is safe to |
FWIW what's also missing here is a testcase that would have lead to breakage in the previous implemenation. |
@wjakob Your first comment is absolutely right, I missed that point, s.t. all functors became single-shot (can be called only once and fail/crash 2nd time). Fixed that in next commit. Had to introduce local "function handle" struct with custom destructor. Seems that my code is working now. Considering testcase: I can write a Python test with statefull lambda, and it should crash Python (and I suppose we can't catch/prevent it in testing code) without this PR and work fine with it. |
e619e19
to
e3375b6
Compare
@wjakob I've made a test case and squashed [NOTE] test leads to segfault (on my machine) if run without latest commit (with previous |
e3375b6
to
296627b
Compare
@wjakob there seems to be a problem with ~func_handle() {
gil_scoped_acquire acq;
function kill_f(std::move(f));
} If I replace it with conventional Python API for acquiring GIL (straight from documentation): ~func_handle() {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
{
function kill_f(std::move(f));
}
PyGILState_Release(gstate);
} then everything works without issues. |
3637a3c
to
9a4eb75
Compare
Hello @wjakob @uentity, I've authored a separate PR #1556 which resolves the deadlock problem with Below is my summary of what I understand of the problems these PRs are trying to solve.
I would love to contribute in any way possible to help resolve these! |
Hi @davidhewitt! With you PR #1556 applied I can bring back my original implementation of ~func_handle() {
gil_scoped_acquire acq;
function kill_f(std::move(f));
} Very soon after I thought my issue #1587 is solved I've faced the issue of your PR #1556 and fixed it by replacing BTW can you give any comment on comparative "heaviness" of capturing GIL solutions I noted earlier? If I look at |
I understand NB I see that #1211 has just been merged which was exactly the same thing that I was trying to solve. So I think that |
9a4eb75
to
b66623f
Compare
func_handle(const func_handle&) = default; | ||
~func_handle() { | ||
gil_scoped_acquire acq; | ||
function kill_f(std::move(f)); |
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.
It might be more clear to explicitly reset the function handle and decrease the reference count: f.release().dec_ref();
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.
Agreed. Done.
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.
@davidhewitt causes strange test failure on VS with Python 3.6 on x86 platform, so reverted back to original version.
Logs: https://ci.appveyor.com/project/wjakob/pybind11/builds/20894165
b66623f
to
60decef
Compare
@wjakob style check is failing because of non-existent URL:
|
60decef
to
b66623f
Compare
I was also affected by this and your patch has unblocked me. Thank you @uentity! |
…1587) Ensure GIL is held during functor destruction.
@hammer498 you're welcome =) |
This looks good to me now. |
Ensure GIL is released after functor destructor finished (not only
during functor execution as in previous implementation).
This fixes #1587