使用嵌入python时增加意外线程

2024-06-28 20:40:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在将python嵌入到我的c++中程序。我的程序将解析iput参数并调用relate python函数。当我运行我的程序时。我发现它的线程保持不变成长。每调用函数“embeddedpython”时,它会增加一个新线程,并且该线程不能被销毁。结果不是我所期望的。我的错在哪里?以下是我的代码:

#include<iostream>
#include<Python.h>
#include<pthread.h>
#include"tools.h"
#include"log.h"
#include"express.h"

int EmbededPython(const string &module, const string &func_name, const vector<Element *> &arg_elmts, string &output, string &errmsg);

int PythonCall(const string &module, const string &funcname, const string &input, string &output, string &errmsg)
{
    vector<string>arg_vec;
    vector<Element *>arg_elmts;
    vector_guard<Element> elmts_guard(arg_elmts);
    char * input_str = (char *)malloc(input.length()+1);
    strcpy(input_str, input.c_str());

    //split will modify the content of string
    split(input_str, arg_vec, ",");
    free(input_str);
    for(unsigned int i = 0; i < arg_vec.size(); i++) {
        trim(arg_vec[i]);
        const char * pExpress = arg_vec[i].c_str();
        ExpressCaculator Caculator(NULL);
        Element *pElement = Caculator.ParseAndCaculate(pExpress);
        if(!pElement) {
            errmsg += "param["+string(pExpress)+"] parsing error";
            return -1;
        }
        arg_elmts.push_back(pElement);
    }

    int ret = 0;
    EmbededPython(module, funcname, arg_elmts, output, errmsg);
    return ret;
}

int EmbededPython(const string &module, const string &func_name, const vector<Element *> &arg_elmts, string &output, string &errmsg)
{
    PyObject *pName, *pModule, *pFunc;
    PyObject *pArgs, *pValue;
    PyObject *pType, *pErrData, *pErrMsg,*pTraceback;

    int ret = 0;

    /* Make sure we own the GIL */
    PyGILState_STATE state = PyGILState_Ensure();

    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\".\")");
    pName = PyString_FromString(module.c_str());
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        pFunc = PyObject_GetAttrString(pModule, func_name.c_str());
        /* pFunc is a new reference */

        if (pFunc && PyCallable_Check(pFunc)) {
            pArgs = PyTuple_New(arg_elmts.size());
            for (unsigned int i = 0; i < arg_elmts.size(); ++i) {
                ParamType data_type = (ParamType)arg_elmts[i]->GetValueType();
                char* data_value = arg_elmts[i]->GetData();
                log_notice("arg[%d]type[%d]value[%s]", i, data_type, data_value);
                if(data_type ==  PARAM_TYPE_INT) {
                    pValue = PyInt_FromLong(atol(data_value));
                } else if(data_type == PARAM_TYPE_FLOAT){
                    pValue = PyFloat_FromDouble(atof(data_value));
                } else {
                    pValue = PyString_FromString(data_value);
                }

                if (!pValue) {
                    Py_DECREF(pArgs);
                    Py_DECREF(pFunc);
                    Py_DECREF(pModule);

                    log_error("Cannot convert argument[%s]", data_value);
                    errmsg += "Cannot convert argument" + string(data_value);
                    ret =  -1;
                    goto PY_FINAL;
                }
                // pValue reference stolen here: 
                PyTuple_SetItem(pArgs, i, pValue);
            }
            /* Make sure we own the GIL */
            //PyGILState_STATE state = PyGILState_Ensure();
            pValue = PyObject_CallObject(pFunc, pArgs);

            //pValue = PyObject_CallObject(pFunc, NULL);
            //PyGILState_Release(state);
            Py_DECREF(pArgs);
            if (pValue != NULL) {
                //Py_DECREF(pValue);
                PyObject *pDictObj;
                PyObject *pStrObj = NULL;

                //get its __dict__ and convert it to string if is class ,module or function
                if(PyClass_Check(pValue) 
                    || PyModule_Check(pValue) 
                    || PyFunction_Check(pValue)) {
                    pStrObj = PyString_FromString("__dict__");
                    pDictObj = PyObject_GetAttr(pValue, pStrObj);
                    Py_DECREF(pStrObj);
                    pStrObj = NULL;
                    if(pDictObj != NULL) {
                        pStrObj = PyObject_Str(pDictObj);
                        Py_DECREF(pDictObj);
                    }
                } else { // direct to convert it to string
                    pStrObj = PyObject_Str(pValue);
                }
                Py_XDECREF(pValue);

                if(pStrObj != NULL) {
                    output.assign(PyString_AsString(pStrObj));
                } else {
                    log_error("Cannot convert result to string");
                    if (PyErr_Occurred()) {
                        PyErr_Fetch(&pType, &pErrData, &pTraceback);
                        pErrMsg = NULL;
                        if(pErrData !=NULL && (pErrMsg = PyObject_Str(pErrData)) != NULL) {
                            errmsg += PyString_AsString(pErrMsg);
                        } else {
                            errmsg += "<unknown exception data>";
                        }

                        Py_XDECREF(pErrMsg);
                        Py_XDECREF(pType);
                        Py_XDECREF(pErrData);
                        Py_XDECREF(pTraceback);
                        PyErr_Clear();
                    }

                    ret = -1;
                }
            } else {
                PyErr_Fetch(&pType, &pErrData, &pTraceback);
                pErrMsg = NULL;
                if(pErrData !=NULL && (pErrMsg = PyObject_Str(pErrData)) != NULL) {
                    errmsg += PyString_AsString(pErrMsg);
                } else {
                    errmsg += "<unknown exception data>";
                }

                Py_XDECREF(pErrMsg);
                Py_XDECREF(pType);
                Py_XDECREF(pErrData);
                Py_XDECREF(pTraceback);
                PyErr_Clear();
                log_error("Call funciton[%s] error",func_name.c_str());
                ret = -1;
            }
        } else {
            if (PyErr_Occurred()) {
                PyErr_Fetch(&pType, &pErrData, &pTraceback);
                pErrMsg = NULL;
                if(pErrData !=NULL && (pErrMsg = PyObject_Str(pErrData)) != NULL) {
                    errmsg += PyString_AsString(pErrMsg);
                } else {
                    errmsg += "<unknown exception data>";
                }

                Py_XDECREF(pErrMsg);
                Py_XDECREF(pType);
                Py_XDECREF(pErrData);
                Py_XDECREF(pTraceback);
                PyErr_Clear();
            }
            log_error("Cannot find function[%s]", func_name.c_str());
            ret = -1;
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    } else {
            PyErr_Fetch(&pType, &pErrData, &pTraceback);
            pErrMsg = NULL;
            if(pErrData !=NULL && (pErrMsg = PyObject_Str(pErrData)) != NULL) {
                errmsg += PyString_AsString(pErrMsg);
            } else {
                errmsg += "<unknown exception data>";
            }

            Py_XDECREF(pErrMsg);
            Py_XDECREF(pType);
            Py_XDECREF(pErrData);
            Py_XDECREF(pTraceback);
            PyErr_Clear();
        log_error("Failed to load module[%s]", module.c_str());
        ret = -1;
    }

PY_FINAL:
    /* Restore previous GIL state and return */
    PyGILState_Release(state);

    return ret;
}

using namespace std;

#define THREAD_SIZE 2
#define RUNTIMES 100000

char* _argv[100] = {};
pthread_t tid[THREAD_SIZE];

void* PyCallQT4S(void *ptr)
{
    string module("QT4SLIB");
    string func_name("GetTGT");

    string input("\"account\",\"passwd\"");
    string output;
    string errmsg;

    for(unsigned int i = 0; i < RUNTIMES; i++) {
        log_notice("run times: %d", i);
        log_notice("input[%s]", input.c_str());
        PythonCall(module, func_name, input, output, errmsg);
        log_notice("PYTHON CALL return[%s]", output.c_str());
        log_notice("PYTHON ERRMSG[%s]", errmsg.c_str());
        errmsg = "";
        output = "";
    }

    return NULL;
}

int main(int argc, char* argv[])
{

    PyThreadState* pyState;
    init_log(argv[0], "../log");
    set_log_pid(false);

    for(int i = 0; i < argc; i++)
        _argv[i] = argv[i];

    Py_Initialize();
    if (!PyEval_ThreadsInitialized()) {
        PyEval_InitThreads();
        pyState = PyEval_SaveThread();
    }

    for(unsigned int i=0; i < THREAD_SIZE; i++) {
        int stacksize = 1024*128;
        pthread_attr_t threadAttr;
        pthread_attr_init(&threadAttr);
        pthread_attr_setstacksize(&threadAttr, stacksize);
        pthread_create(tid+i, &threadAttr, PyCallQT4S, NULL);
    }

    for(unsigned int i=0; i < THREAD_SIZE; i++) {
        pthread_join(tid[i], NULL);
    }

    cout <<"all thread finish!"<< endl;

    if (PyEval_ThreadsInitialized()) {
        PyEval_RestoreThread(pyState);
    }

    Py_Finalize();

    return 0;
}

Tags: pylogdatastringifargnullint