2013-05-17 6 views
13

से पाइथन विधि को कॉल करना मैं सी ++ से एक पायथन कक्षा में विधियों को कॉल करने का प्रयास कर रहा हूं। सी ++ विधि जिसे इसे कहा जाता है वह एक सी ++ कॉलबैक है।सी ++ (या सी) कॉलबैक

इस विधि के भीतर जब मैं पायथन विधि को कॉल करने का प्रयास कर रहा हूं, तो यह segmentation fault दे रहा था।

मैं की तरह

// (pFunc is global variable of type PyObject*) 
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper"); 

जहां PlxMsgWrapper एक अजगर विधि है, जो कॉलबैक में इस्तेमाल किया जाएगा एक वैश्विक चर में अजगर समारोह का एक उदाहरण बचाया है।

कॉलबैक में जब

PyObject * pInstance = PyObject_CallObject(pFunc, args); 

बनाने इस लाइन अपने विभाजन गलती देने में, तर्कों के रूप

PyObject* args = PyTuple_Pack(2, PyString_FromString(header.c_str()), 
           PyString_FromString(payload.c_str())); 

बनाई गई हैं। इस के बाद वास्तविक अजगर विधि

के रूप में कहा जाता है
PyObject* recv_msg_func = PyObject_GetAttrString(module, (char *)"recvCallback"); 
args = PyTuple_Pack(1, pInstance); 
PyObject_CallObject(recv_msg_func, args); 
+0

मैंने सही तरीके से स्पष्ट करने की पूरी कोशिश की है।यदि कोई समस्या है तो कृपया टिप्पणी करें। – Chaitanya

+0

क्या आपने जांच की है कि PyObject_GetAttrString वास्तव में कुछ उपयोग करने योग्य देता है? हो सकता है कि लुकअप किसी कारण से विफल हो। शायद 'मॉड्यूल' सही ढंग से शुरू नहीं किया गया था? – djf

+0

@ डीजेएफ दरअसल, नियंत्रण उस बिंदु तक नहीं आ रहा है। 'PyObject_CallObject (pFunc, args)'। इस विधि को स्वयं कॉल करते समय यह दुर्घटनाग्रस्त हो रहा है। मॉड्यूल की समस्याओं से छुटकारा पाने के लिए, मैं इसे कॉलबैक में लोड नहीं कर रहा हूं। – Chaitanya

उत्तर

27

कुछ चीजें आपको बस इतना करना है यदि आप एक C/C++ कॉलबैक से एक अजगर समारोह लागू कर रहे हैं। सबसे पहले जब आप अपने अजगर समारोह वस्तु बंद बचाने के लिए, आप के साथ संदर्भ संख्या में भी वृद्धि की जरूरत है:

Py_INCREF(pFunc) 

अन्यथा अजगर पता नहीं आप एक वस्तु संदर्भ पर पकड़े हुए हैं है, और यह कचरा यह एकत्र कर सकते हैं, एक विभाजन में जिसके परिणामस्वरूप जब आप इसे अपने कॉलबैक से उपयोग करने का प्रयास करते हैं तो गलती।

फिर अगली बात आपको चिंतित होने की आवश्यकता है कि आपका सी/सी ++ कॉलबैक कब लागू होता है। यदि आपको किसी अन्य गैर-पायथन द्वारा निर्मित थ्रेड (यानी एक सी/सी ++ थ्रेड डेटा को सॉकेट पर प्राप्त करने से वापस बुलाया जा रहा है), तो आप किसी भी पायथन एपीआई फ़ंक्शंस को कॉल करने से पहले पायथन के ग्लोबल इंटरप्रेटर लॉक (जीआईएल) प्राप्त कर सकते हैं। अन्यथा आपके कार्यक्रम का व्यवहार अपरिभाषित है। जीआईएल प्राप्त करने के लिए आप करते हैं:

// Make sure the GIL has been created since we need to acquire it in our 
// callback to safely call into the python application. 
if (! PyEval_ThreadsInitialized()) { 
    PyEval_InitThreads(); 
} 

अन्यथा, दुर्घटनाओं और अनोखा व्यवहार कर सकते हैं:

void callback() { 
    PyGILState_STATE gstate; 
    gstate = PyGILState_Ensure(); 

    // Get args, etc. 

    // Call your Python function object 
    PyObject * pInstance = PyObject_CallObject(pFunc, args); 

    // Do any other needed Python API operations 

    // Release the thread. No Python API allowed beyond this point. 
    PyGILState_Release(gstate); 
} 

इसके अलावा, अपने विस्तार मॉड्यूल के init समारोह में, आप उस सूत्रण सुनिश्चित करने के लिए निम्नलिखित ठीक से प्रारंभ कर रहा है क्या करना चाहिए जब आप गैर-पायथन धागे से जीआईएल हासिल करने का प्रयास करते हैं तो तब आते हैं।

इस पर अधिक जानकारी के लिए Non-Python Created Threads देखें।

+1

बहुत बहुत धन्यवाद। :) वह सही समस्या थी। – Chaitanya

+0

बहुत बहुत धन्यवाद - मुझे नहीं लगता था कि मैं गलत धागे में हो सकता हूं। – eddiewould

2

अजगर, निर्देशिका जहां यह तथापि, से रन किया जा रहा है में एक मॉड्यूल के लिए दिखना चाहिए अगर आपको लगता है कि मुद्दा यह है कि अजगर अपनी फ़ाइल ढूंढने नहीं है , तो आप अपने कार्यक्रम के भीतर मॉड्यूल खोज पथ के लिए अपने कंप्यूटर पर एक मनमाना निर्देशिका जोड़ सकते हैं:

// Initialize the Python Interpreter 
Py_Initialize(); 

// The following two lines to the trick: 
// add path to your module to python's search paths 
PyRun_SimpleString("import sys"); 
PyRun_SimpleString("sys.path.append(\"/path/to/python/module/here\")"); 

// Build the name object 
pName = PyString_FromString("your_module"); 

// Load the module object 
pModule = PyImport_Import(pName); 

// pDict is a borrowed reference 
pDict = PyModule_GetDict(pModule); 

// pFunc is also a borrowed reference 
pFunc = PyDict_GetItemString(pDict, "PlxMsgWrapper"); 

pArgs = ... 

if (PyCallable_Check(pFunc)) 
{ 
    PyObject_CallObject(pFunc, pArgs); 
} else { 
    PyErr_Print(); 
} 
2

यह आपके प्रश्न का बिल्कुल जवाब नहीं देता है, लेकिन आप अपने कोड को बहुत सरल बना सकते हैं और Boost::Python के साथ संदर्भ गणना समस्याओं से बच सकते हैं।

#include "boost/python.hpp" 

using namespace boost::python; 

int main() 
{ 
    Py_Initialize(); 

    object pyFunPlxMsgWrapper = import("your_module").attr("PlxMsgWrapper"); 
    pyFunPlxMsgWrapper(2, "string", "data"); 
    return 0; 
} 
संबंधित मुद्दे