Skip to content

Commit

Permalink
python: wrap python_async_result::iterator to free GIL in long operat…
Browse files Browse the repository at this point in the history
…ions

Some operations on iterator cause waiting for new responses and without releasing GIL it sometimes leads to deadlock.
  • Loading branch information
shaitan committed Jul 25, 2016
1 parent 6873fda commit f7b36e4
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 9 deletions.
49 changes: 47 additions & 2 deletions bindings/python/async_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,53 @@ error get_async_result_error(const python_async_result<T> &async) {
}

template <typename T>
struct def_async_result<T>
{
typename python_async_result<T>::iterator &python_async_result<T>::iterator::operator=(const iterator &other) {
py_allow_threads_scoped pythr;
m_inner = other.m_inner;
return *this;
}

template <typename T>
bool python_async_result<T>::iterator::operator==(const iterator &other) const {
py_allow_threads_scoped pythr;
return m_inner == other.m_inner;
}

template <typename T>
bool python_async_result<T>::iterator::operator!=(const iterator &other) const {
py_allow_threads_scoped pythr;
return m_inner != other.m_inner;
}

template <typename T>
T python_async_result<T>::iterator::operator*() const {
py_allow_threads_scoped pythr;
return *m_inner;
}

template <typename T>
T *python_async_result<T>::iterator::operator->() const {
py_allow_threads_scoped pythr;
return m_inner.operator->();
}

template <typename T>
typename python_async_result<T>::iterator &python_async_result<T>::iterator::operator++() {
py_allow_threads_scoped pythr;
++m_inner;
return *this;
}

template <typename T>
typename python_async_result<T>::iterator python_async_result<T>::iterator::operator++(int) {
py_allow_threads_scoped pythr;
iterator tmp(m_inner);
++m_inner;
return tmp;
}

template <typename T>
struct def_async_result<T> {
static void init() {
bp::class_<python_async_result<T>>(
"AsyncResult", "Future for waiting/getting results from asynchronous execution of operation")
Expand Down
35 changes: 28 additions & 7 deletions bindings/python/async_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,39 @@ struct callback_one_handlers {
};

template <typename T>
struct python_async_result
{
typedef typename async_result<T>::iterator iterator;

std::shared_ptr<async_result<T>> scope;
struct python_async_result {
class iterator : public std::iterator<std::input_iterator_tag, T, std::ptrdiff_t, T *, T> {
public:
iterator()
: m_inner() {}
iterator(const typename async_result<T>::iterator &other)
: m_inner(other) {}
iterator(const iterator &other)
: m_inner(other.m_inner) {}
~iterator() {}

iterator &operator=(const iterator &other);

bool operator==(const iterator &other) const;
bool operator!=(const iterator &other) const;

T operator*() const;
T *operator->() const;

iterator &operator ++();
iterator operator ++(int);
private:
typename async_result<T>::iterator m_inner;
};

iterator begin() {
py_allow_threads_scoped pythr;
return scope->begin();
return iterator{scope->begin()};
}

iterator end() {
py_allow_threads_scoped pythr;
return scope->end();
return iterator{scope->end()};
}

bp::list get() {
Expand Down Expand Up @@ -152,6 +171,8 @@ struct python_async_result
auto callback = boost::make_shared<callback_all_handler<T>>(handler);
scope->connect(boost::bind(&callback_all_handler<T>::on_results, callback, _1, _2));
}

std::shared_ptr<async_result<T>> scope;
};

template <typename T>
Expand Down

0 comments on commit f7b36e4

Please sign in to comment.