6

Tôi đã viết mô-đun mở rộng sử dụng các con trỏ hàm C++ để lưu trữ chuỗi các cuộc gọi hàm. Tôi muốn 'chạy' các chuỗi cuộc gọi này trong các quy trình riêng biệt sử dụng mô-đun multiprocessing của python (không có trạng thái chia sẻ nào, do đó không có sự cố đồng bộ hóa).Các con trỏ hàm có còn hợp lệ trong các quy trình không?

Tôi cần biết liệu con trỏ hàm (không phải con trỏ dữ liệu) có còn hợp lệ sau multiprocessing không là fork().

C++ mô-đun:

#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); 
} 

Biên soạn với:

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

mã Python gọi nó qua nhiều quy trình:

#!/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() 

Kết quả được như mong đợi. Tôi muốn biết nếu tôi chỉ 'may mắn' hoặc nếu tôi có thể tin tưởng một cách đáng tin cậy các con trỏ chức năng vẫn còn hiệu lực sau một số fork().

Trả lời

4

Chắc chắn - không gian địa chỉ được sao chép khi bạn ngã ba, vì vậy các con trỏ vẫn hợp lệ sau đó cho cả quá trình cha và con.

+0

Về nhận xét của bạn về câu trả lời (hiện đã bị xóa) của tôi, đó là vì tôi không biết 'fork' sao chép không gian địa chỉ. Câu trả lời của tôi là đúng cho hai quá trình hoàn toàn không liên quan, mà tôi nghĩ là cái 'ngã ba', nhưng tất nhiên là tôi đã sai. +1 –

+1

Trên Windows nó không ngã ba, nhưng chạy một trình thông dịch Python mới. Tôi nghĩ rằng điều này cũng sẽ làm việc tốt với mã của OP. Xem tại đây: http://bugs.python.org/issue8713 –