如何获取python's multiprocessing array'指针并将其传递给Cpp程序?

How to get python's multiprocessing array'pointer and pass it to Cpp program?

我现在需要在 python 中请求数组,并将它们传递给 Cpp 程序,但 python 仍然需要处理它们。但是我发现当我使用multiprocessing时,数组的地址会被改变。

下面是我的代码:

//export dll in test.h, this is test.cpp
#include "test.h"
#include <iostream>
using namespace std;

void someWork(double* data, long* flag){
    cout << "cpp flag address:" << flag << endl;
    //do some work
}
# test.py
import multiprocessing as mp
from multiprocessing.sharedctypes import RawArray
import ctypes

data = RawArray(ctypes.c_double, 2000)
flag = RawArray(ctypes.c_long, 20)
pkg = ctypes.cdll.LoadLibrary(r"test.dll")
pkg.someWork.argtypes = [
    ctypes.POINTER(ctypes.c_double * 2000),# dataArray
    ctypes.POINTER(ctypes.c_long * 20)#flagArray
]

def proc_py():
    idx = 0
    while True:
        if flag[idx] == 1:
            # do something
            flag[idx] = 0
            idx = (idx + 1) % 20

def proc_cpp():
    pkg.someWork(ctypes.pointer(data), ctypes.pointer(flag))

def main():
    p_cpp = mp.Process(target=proc_cpp, args=())
    p_py = mp.Process(target=proc_py, args=())
    p_cpp .start()
    p_py .start()
    p_cpp .join()
    p_py .join()

if __name__ == '__main__':
    print("py flag address:", ctypes.byref(flag))
    # proc_cpp()
    main()

结果是:当我在python中运行proc_cpp时,地址是一样的:

py flag address: <cparam 'P' (0000019DA8282400)>
cpp flag address:   0000019DA8282400

但是我运行main的时候,地址不一样:

py flag address: <cparam 'P' (000001CB42A32400)>
cpp flag address:   0000012F1E152400

我知道 python 的多进程必须使用共享内存来在进程之间共享内存,但是我使用 mp.Array/Array.get_obj()mp.sharedctypes.RawArray/ 都失败了ctypes.pointer()。有什么办法可以解决我的问题吗?

不要在“运行 once”主代码之外创建 RawArray,否则您正在创建 不同的 数组。在主进程中创建一次 RawArray,并将该 RawArray 作为参数传递给新进程的目标函数。每个进程“看到”的虚拟地址会不同,但物理内存是一样的。

这是一个例子:

test.cpp:

这将显示指针地址,然后更改共享数组中的指定索引。

#include <iostream>
#include <cstdint>
using namespace std;

#define API __declspec(dllexport)

extern "C" API
void set(double* data, int index, double value) {
    cout << data << ' ' << index << ' ' << value << endl;
    data[index] = value;
}

test.py:

这会将共享数组传递给每个进程。主进程也会改变一个元素。使用锁是因为 RawArray 不同步,否则 C++ 代码中的打印会搞砸,所以这段代码不会真正 运行 并行,但它确实说明了进程获得不同的虚拟地址但共享相同的数据。

import multiprocessing as mp
from multiprocessing.sharedctypes import RawArray
from ctypes import *

dll = CDLL('./test')
dll.set.argtypes = POINTER(c_double),c_int,c_double
dll.set.restype = None

def call(lock,data,index,value):
    with lock:
        dll.set(data,index,value)

if __name__ == '__main__':

    # This code runs once in the main process.
    # The lock and shared data are created once only and passed to other processes.

    lock = mp.Lock()
    data = RawArray(c_double, 3)
    data[0] = 0.5
    p1 = mp.Process(target=call, args=(lock,data,1,1.25))
    p2 = mp.Process(target=call, args=(lock,data,2,2.5))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(list(data))

输出(不同地址,相同共享数据):

00000269D66E0000 1 1.25
00000187F0B90000 2 2.5
[0.5, 1.25, 2.5]