2013-07-15 3 views
2

파이썬 목록에 대한 참조를 boost :: python C++ dll에 전달할 수 있는지 알고 싶습니다. 내가 성취하고자하는 것은 파이썬에서 언제든지 C++로 읽을 수있는 목록을 가지고 있다는 것입니다. 목록에 대한 참조를 보유하는 C++의 변수가 있다고 가정 해 봅니다.boost :: python python :: list에 대한 참조를 전달하는 중

이렇게 할 방법이 있습니까? 지금까지 파이썬에서 ctypes를 찾았습니다. 여기서 원시적 인 C 타입에 대한 참조를 만들 수 있습니다.이 경우에는 도움이되지 않습니다.

내가 (간단한 예제가 좋은 것) 제안이나 해결 방법에 대한 행복

인사말 한마디로 크리스

답변

6

, Boost.Python은 TypeWrappers와 의미를 전달 파이썬 인수를 유지한다. 따라서 Python에서 노출 된 C++ 함수로 목록을 전달할 때 Python 목록을 boost::python::list 객체로 받아들임으로써 참조를 만들고 유지 관리 할 수 ​​있습니다.


상세한 답변은 실제로 좀 더 깊이 있습니다. 그것을 탐구하기 전에 혼동을 피하기 위해 몇 가지 의미를 확장하겠습니다. 파이썬의 가비지 콜렉션과 객체 별 의미론을 통해, 일반적인 경험 법칙은 Boost.Python TypeWrappers를 스마트 포인터로 취급하는 것입니다.

  • 이 함수가 목록을 boost::python::list 개체로 허용하면 C++에 이제 Python 개체에 대한 참조가 있습니다. 파이썬리스트의 수명은 최소한 booot::python::list 객체만큼 길어질 것입니다.
  • 파이썬 목록이 std::vector과 같이 다른 유형으로 변환 된 경우 C++에서 파이썬 목록에 대한 복사본을 생성했습니다. 이 사본은 원래 목록과 관련이 없습니다.

    #include <iostream> // std::cout 
    #include <utility> // std::make_pair 
    #include <boost/foreach.hpp> 
    #include <boost/python.hpp> 
    #include <boost/python/stl_iterator.hpp> 
    
    boost::python::list list; 
    
    /// @brief Store handle to the list. 
    /// 
    /// @param pylist Python list for which a handle will be maintained. 
    void set(const boost::python::list& pylist) 
    { 
        // As the boost::python::list object is smart-pointer like, this 
        // creates a reference to the python list, rather than creating a 
        // copy of the python list. 
        list = pylist; 
    } 
    
    // Iterate over the current list, printing all ints. 
    void display() 
    { 
        std::cout << "in display" << std::endl; 
        typedef boost::python::stl_input_iterator<int> iterator_type; 
        BOOST_FOREACH(const iterator_type::value_type& data, 
           std::make_pair(iterator_type(list), // begin 
               iterator_type())) // end 
        { 
        std::cout << data << std::endl; 
        } 
    } 
    
    BOOST_PYTHON_MODULE(example) { 
        namespace python = boost::python; 
        python::def("set",  &set); 
        python::def("display", &display); 
    } 
    

    그리고 그것의 사용 : : 여기

은 핸들을 유지하고, 그 내용을 인쇄, 파이썬 목록을 전달할 수있는 C의 ++ 모듈의 간단한 예입니다

>>> import example 
>>> 
>>> x = range(2) 
>>> x 
[0, 1] 
>>> example.set(x) 
>>> example.display() 
in display 
0 
1 
>>> x[:] = range(7, 10) 
>>> example.display() 
in display 
7 
8 
9 

질문에서 소개되는 복잡성 중 하나는 언제든지 에있는 C++의 Python 목록을 읽으려는 것입니다. 가장 복잡한 경우은 언제든지 C++ 스레드 내에서 발생할 수 있습니다. 언제든지이 발생할 수 있습니다.

기본적으로 시작하자. Python의 Global Interpreter Lock (GIL). 즉, GIL은 통역사 주위의 뮤텍스입니다. 쓰레드가 파이썬 관리 객체의 참조 카운팅에 영향을 미치는 것이 있다면, GIL을 획득해야합니다. 때때로 참조 횟수가 매우 투명하지, 고려 : 일정한 기준으로 list을 받아

typedef boost::python::stl_input_iterator<int> iterator_type; 
iterator_type iterator(list); 

boost::python::stl_input_iterator 있지만 생성자 내에서 파이썬 목록에 대한 참조를 만듭니다.

위의 예에서 C++ 스레드가 없었기 때문에 GIL을 획득하는 동안 모든 동작이 발생했습니다.그러나 display()이 C++ 내에서 언제든지 호출 될 수 있으면 몇 가지 설정이 필요합니다.

먼저, 모듈은 파이썬이 스레딩을 위해 GIL을 초기화해야합니다. 편의를 위해

BOOST_PYTHON_MODULE(example) { 
    PyEval_InitThreads(); // Initialize GIL to support non-python threads. 
    ... 
} 

가 관리하는 GIL 도움이되는 간단한 클래스 만들 수 있습니다 :

/// @brief RAII class used to lock and unlock the GIL. 
class gil_lock 
{ 
public: 
    gil_lock() { state_ = PyGILState_Ensure(); } 
    ~gil_lock() { PyGILState_Release(state_); } 
private: 
    PyGILState_STATE state_; 
}; 

는 C++ 스레드와 상호 작용을 표시하려면를, 응용 프로그램이 일정 할 수 있도록 모듈에 기능을 추가 할 수 있습니다 목록의 내용이 표시 될 때까지 지연됩니다.

#include <iostream> // std::cout 
#include <utility> // std::make_pair 
#include <boost/foreach.hpp> 
#include <boost/python.hpp> 
#include <boost/python/stl_iterator.hpp> 
#include <boost/thread.hpp> 

boost::python::list list; 

/// @brief Store handle to the list. 
/// 
/// @param pylist Python list for which a handle will be maintained. 
void set(const boost::python::list& pylist) 
{ 
    list = pylist; 
} 

// Iterate over the current list, printing all ints. 
void display() 
{ 
    std::cout << "in display" << std::endl; 
    typedef boost::python::stl_input_iterator<int> iterator_type; 
    BOOST_FOREACH(const iterator_type::value_type& data, 
       std::make_pair(iterator_type(list), // begin 
           iterator_type())) // end 
    { 
    std::cout << data << std::endl; 
    } 
} 

/// @brief RAII class used to lock and unlock the GIL. 
class gil_lock 
{ 
public: 
    gil_lock() { state_ = PyGILState_Ensure(); } 
    ~gil_lock() { PyGILState_Release(state_); } 
private: 
    PyGILState_STATE state_; 
}; 

/// @brief Entry point for delayed display thread. 
/// 
/// @param Delay in seconds. 
void display_in_main(unsigned int seconds) 
{ 
    boost::this_thread::sleep_for(boost::chrono::seconds(seconds)); 
    gil_lock lock; // Acquire GIL. 
    display();  // Can safely modify python objects. 
    // GIL released when lock goes out of scope. 
} 

/// @brief Schedule the list to be displayed. 
/// 
/// @param Delay in seconds. 
void display_in(unsigned int seconds) 
{ 
    // Start detached thread. 
    boost::thread(&display_in_main, seconds).detach(); 
} 

BOOST_PYTHON_MODULE(example) { 
    PyEval_InitThreads(); // Initialize GIL to support non-python threads. 

    namespace python = boost::python; 
    python::def("set",  &set); 
    python::def("display", &display); 
    python::def("display_in", &display_in); 
} 

그리고 그것의 사용 : : 여기

/// @brief Entry point for delayed display thread. 
/// 
/// @param Delay in seconds. 
void display_in_main(unsigned int seconds) 
{ 
    boost::this_thread::sleep_for(boost::chrono::seconds(seconds)); 
    gil_lock lock; // Acquire GIL. 
    display();  // Can safely modify python objects. 
    // GIL released when lock goes out of scope. 
} 

/// @brief Schedule the list to be displayed. 
/// 
/// @param Delay in seconds. 
void display_in(unsigned int seconds) 
{ 
    // Start detached thread. 
    boost::thread(&display_in_main, seconds).detach(); 
} 

은 완전한 예입니다

>>> import example 
>>> from time import sleep 
>>> 
>>> x = range(2) 
>>> example.set(x) 
>>> example.display() 
in display 
0 
1 
>>> example.display_in(3) 
>>> x[:] = range(7, 10) 
>>> print "sleeping" 
sleeping 
>>> sleep(6) 
in display 
7 
8 
9 

sleep(6) 전화 6 초 동안 차단 파이썬 콘솔의 C++ 스레드가 GIL를 인수하면서 목록 x의 내용을 표시하고 GIL을 릴리스했습니다.

+0

감사의 말씀을 전하고 싶습니다. 아마도 C++에 대한 목록 참조를 얻으려고 시도했을 때 약간의 실수를 저질렀습니다. 여기에 멀티 스레딩과 관련하여 stackoverflow에 또 다른 질문이 있습니다. 나는 잠금까지 생각하기까지는 그다지 멀지 않았다. 그래서 기본적으로 당신은 제가 기대했던 것보다 더 많은 것을 도왔습니다. (제 질문의 약 1/2) 그리고 오늘 나를 기뻤습니다. D 아주 많이 다시 한번 감사드립니다. –

+0

@ 크리스 : 도와 줘서 기뻐요. (Boost.Python의 질문에 [tag : boost-python] 태그로 태그를 지정하면 더 많은 잠재 고객에게 다가 갈 수 있습니다. –