Skip to content

Commit ce25b36

Browse files
authored
Release the GIL before any call to async methods (#123)
Fix #122 When call an async method on Pulsar C++ client, we need to be releasing the GIL to avoid a deadlock between that and the producer lock.
1 parent 0d1402a commit ce25b36

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

src/utils.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,16 @@
2121

2222
void waitForAsyncResult(std::function<void(ResultCallback)> func) {
2323
auto promise = std::make_shared<std::promise<Result>>();
24-
func([promise](Result result) { promise->set_value(result); });
24+
25+
{
26+
// Always call the Pulsar C++ client methods without holding
27+
// the GIL. This avoids deadlocks due the sequence of acquiring
28+
// mutexes by different threads. eg:
29+
// Thread-1: GIL -> producer.lock
30+
// Thread-2: producer.lock -> GIL (In a callback)
31+
py::gil_scoped_release release;
32+
func([promise](Result result) { promise->set_value(result); });
33+
}
2534
internal::waitForResult(*promise);
2635
}
2736

src/utils.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ inline T waitForAsyncValue(std::function<void(std::function<void(Result, const T
4949
auto resultPromise = std::make_shared<std::promise<Result>>();
5050
auto valuePromise = std::make_shared<std::promise<T>>();
5151

52-
func([resultPromise, valuePromise](Result result, const T& value) {
53-
valuePromise->set_value(value);
54-
resultPromise->set_value(result);
55-
});
52+
{
53+
py::gil_scoped_release release;
54+
55+
func([resultPromise, valuePromise](Result result, const T& value) {
56+
valuePromise->set_value(value);
57+
resultPromise->set_value(result);
58+
});
59+
}
5660

5761
internal::waitForResult(*resultPromise);
5862
return valuePromise->get_future().get();

0 commit comments

Comments
 (0)