demo race when using call_guard<gil_scoped_release> and implicitly_convertible

This commit is contained in:
Mana 2020-12-07 18:59:27 +08:00
parent 028812ae7e
commit 5f3d8d806a
2 changed files with 57 additions and 0 deletions

View File

@ -97,5 +97,31 @@ TEST_SUBMODULE(call_policies, m) {
m.def("with_gil", report_gil_status); m.def("with_gil", report_gil_status);
m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>()); m.def("without_gil", report_gil_status, py::call_guard<py::gil_scoped_release>());
class MyInt {
public:
MyInt(int i)
: i_(i)
{}
int i_;
};
py::class_<MyInt>(m, "MyInt")
.def(py::init<int>());
py::implicitly_convertible<int, MyInt>();
// This function races
m.def("guard_without_gil_implicit_conversion",
[](MyInt my_int) {
return my_int.i_;
},
py::call_guard<py::gil_scoped_release>());
// This function works fine
m.def("without_gil_implicit_conversion",
[](MyInt my_int) {
py::gil_scoped_release gil_release;
return my_int.i_;
});
#endif #endif
} }

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import pytest import pytest
import threading
import env # noqa: F401 import env # noqa: F401
@ -217,3 +218,33 @@ def test_call_guard():
if hasattr(m, "with_gil"): if hasattr(m, "with_gil"):
assert m.with_gil() == "GIL held" assert m.with_gil() == "GIL held"
assert m.without_gil() == "GIL released" assert m.without_gil() == "GIL released"
@pytest.mark.parametrize(
"test_func",
["guard_without_gil_implicit_conversion", "without_gil_implicit_conversion"],
)
def test_without_gil_implicit_conversion(test_func):
try:
func = getattr(m, test_func)
except AttributeError:
return
num_threads = 16
def check(results, i):
results[i] = func(42) == 42
results = [None] * num_threads
for _ in range(int(1e4)):
threads = []
for i in range(num_threads):
thread = threading.Thread(target=check, args=(results, i))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
ok = all(results)
if not ok:
raise AssertionError(results)