6

C++ 함수 포인터를 사용하여 함수 호출 시퀀스를 저장하는 확장 모듈을 작성했습니다. 파이썬의 multiprocessing 모듈 (공유 상태가 없으므로 동기화 문제가 없음)을 사용하여 이러한 호출 순서를 별도의 프로세스에서 '실행'하고 싶습니다.함수 포인터는 프로세스에서 유효합니까?

multiprocessing 이후에 함수 포인터 (데이터 포인터 아님)가 유효한 지 알아야합니다. fork()입니다.

C++ 모듈 :

#include <list> 
#include <boost/assert.hpp> 
#include <boost/python.hpp> 
#include <boost/python/stl_iterator.hpp> 
#include <boost/foreach.hpp> 

/* 
* Some functions to be called 
*/ 
double funcA(double d) { return d; } 
double funcB(double d) { return d + 3.14; } 
double funcC(double d) { return d - 42.0; } 

/* 
* My container of function pointers (picklable to allow use with multiprocessing) 
*/ 
typedef double(*func_ptr_t)(double); 
struct CallSequence { 
    CallSequence() { 
     _seq.push_back(funcA); 
     _seq.push_back(funcB); 
     _seq.push_back(funcC); 
    } 

    std::list<func_ptr_t> _seq; 
}; 

template <typename cast_type> 
struct CallSequence_picklesuite : boost::python::pickle_suite { 
    BOOST_STATIC_ASSERT_MSG(sizeof(cast_type) == sizeof(func_ptr_t), CANNOT_CAST_POINTER_TO_REQUESTED_TYPE); 

    static boost::python::list getstate(const CallSequence& cs) { 
     boost::python::list ret; 
     BOOST_FOREACH(func_ptr_t p, cs._seq) 
      ret.append(reinterpret_cast<cast_type>(p)); 
     return ret; 
    } 

    static void setstate(CallSequence& cs, boost::python::list l) { 
     std::list<func_ptr_t> new_list; 
     boost::python::stl_input_iterator<cast_type> begin(l), end; 
     for(; begin != end; begin++) 
      new_list.push_back(reinterpret_cast<func_ptr_t>(*begin)); 
     cs._seq.swap(new_list); 
    } 
}; 

/* 
* Run the call sequence 
*/ 
double runner(const CallSequence& cs) { 
    double ret = 0; 
    BOOST_FOREACH(const func_ptr_t& p, cs._seq) 
     ret += p(2.18); 
    return ret; 
} 

BOOST_PYTHON_MODULE(my_extension) { 
    using namespace ::boost::python; 

    class_<CallSequence>("CallSequence") 
     .def_pickle(CallSequence_picklesuite<unsigned int>()); 
    def("runner", runner); 
} 

컴파일 : 여러 프로세스를 통해 그것을 호출

$ g++ question1.cpp -lboost_python -I /usr/include/python2.7 -shared -o my_extension.so 

파이썬 코드 :

#!/usr/bin/python 

from multiprocessing import Pool 

import my_extension 

def runner(sequence): 
    return my_extension.runner(sequence) 

def main(): 
    l = [my_extension.CallSequence() for _ in range(200)] 

    pool = Pool(processes=4) 
    print pool.map(runner, l) 

if __name__ == '__main__': 
    main() 

가 출력이 예상한다. 나는 단지 '운이 좋았는지'또는 fork() 이후에 함수 포인터가 유효하게 유지 될 것이라고 확실히 신뢰할 수 있는지 알고 싶습니다.

답변

4

확실히 - 주소 공간은 포크 할 때 복사되므로 부모와 자식 프로세스 모두에 대해 포인터가 유효합니다.

+0

내 (지금 삭제 된) 답변에 대한 귀하의 의견에 대해서는 '포크 (fork)'가 주소 공간을 복사했기 때문에 발생했습니다. 내 대답은 완전히 관련이없는 두 개의 프로세스에 맞았을 것이다. 나는'fork '가하는 일이라고 생각했지만 물론 틀렸다. +1 –

+1

Windows에서는 포크를 실행하지 않지만 새로운 파이썬 인터프리터를 실행합니다. 나는 이것이 OP의 코드에서도 잘 작동 할 것이라고 생각한다. 여기를 참조하십시오 : http://bugs.python.org/issue8713 –