函数指针跨进程是否仍然有效?

6

我写了一个扩展模块,使用C++函数指针来存储函数调用序列。我想使用Python的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

在多个进程中调用Python代码:

#!/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()之后保持有效。

1个回答

4
当您进行fork操作时,地址空间会被复制,因此指针在父进程和子进程中仍然有效。

关于您对我(现已删除的)答案的评论,原因是我不知道fork会复制地址空间。我的答案对于两个完全不相关的进程是正确的,我认为这就是fork的作用,但当然我错了。+1 - Seth Carnegie
1
在Windows上,它不会分叉,而是运行一个新的Python解释器。我认为这对于OP的代码也可以正常工作。请参见此处:http://bugs.python.org/issue8713 - John Zwinck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接