带有C扩展和线程的python中的segfault

时间:2017-06-13 14:16:20

标签: python c multithreading

我正在为Python编写一个C扩展,它在cpython解释器之外的Linux上使用本机pthread。我读了GIL和AFAIK我根据python 2.7文档做了一切。

而且,只要我不启动其他python线程,一切都很好。但是,我想创建一个单元测试脚本,它启动我需要在python线程中与之交谈的服务器。一旦我这样做,程序就会崩溃,向我表明我正在对GIL做错事。这是GDB的回溯:

Core was generated by `/usr/bin/python ./test.py'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004cc69f in PyEval_EvalFrameEx ()
(gdb) bt
#0  0x00000000004cc69f in PyEval_EvalFrameEx ()
#1  0x00000000004e4518 in ?? ()
#2  0x00000000004ccd09 in PyEval_EvalFrameEx ()
#3  0x00000000004c996a in PyEval_EvalFrameEx ()
#4  0x00000000004c996a in PyEval_EvalFrameEx ()
#5  0x00000000004e4518 in ?? ()
#6  0x0000000000502ab8 in ?? ()
#7  0x00000000004d0f2b in PyEval_CallObjectWithKeywords ()
#8  0x00000000005bc202 in ?? ()
#9  0x00007f3198b86064 in start_thread (arg=0x7f3196c91700) at pthread_create.c:309
#10 0x00007f3197f9862d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

线程非常简单:

command = [server_path, '-s', sockpath]
log.info("command is %s", command)

def runserver(command):
    log.info("in runserver")
    pipe = subprocess.Popen(command,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            shell=False)
    log.info("pipe open")
    line = pipe.stdout.readline()
    while line:
        line = line.rstrip()
        # Handle unicode
        try:
            line = line.decode('utf8', 'replace')
            log.info(line)
        except UnicodeDecodeError, err:
            log.error("failed to handle line: %s", str(err))
        line = pipe.stdout.readline()

server_thread = threading.Thread(target=runserver, kwargs={'command': command})
server_thread.daemon = True
log.info("starting server thread")
server_thread.start()

这是我的C扩展的初始化。

// Our module entry point.
PyMODINIT_FUNC initlibinipy(void) {
    PyObject *m;

    m = Py_InitModule3("libinipy", libinipy_methods, "FIXME: put docstring here");
    if (m == NULL)
        return;

    /*
     * Create our exception types. IniDbError is the base class of all exceptions in
     * this library.
     */
    IniDbError = PyErr_NewException("libinipy.IniDbError", NULL, NULL);
    Py_INCREF(IniDbError);
    PyModule_AddObject(m, "IniDbError", IniDbError);

    IniDbConnectError = PyErr_NewException("libinipy.IniDbConnectError", IniDbError, NULL);
    Py_INCREF(IniDbConnectError);
    PyModule_AddObject(m, "IniDbConnectError", IniDbConnectError);

    IniDbFlushError = PyErr_NewException("libinipy.IniDbFlushError", IniDbError, NULL);
    Py_INCREF(IniDbFlushError);
    PyModule_AddObject(m, "IniDbFlushError", IniDbFlushError);

    IniDbBadParamError = PyErr_NewException("libinipy.IniDbBadParamError", IniDbError, NULL);
    Py_INCREF(IniDbBadParamError);
    PyModule_AddObject(m, "IniDbBadParamError", IniDbBadParamError);

    IniDbBadHandleError = PyErr_NewException("libinipy.IniDbBadHandleError", IniDbError, NULL);
    Py_INCREF(IniDbBadHandleError);
    PyModule_AddObject(m, "IniDbBadHandleError", IniDbBadHandleError);

    IniDbFileNotFoundError = PyErr_NewException("libinipy.IniDbFileNotFoundError", IniDbError, NULL);
    Py_INCREF(IniDbFileNotFoundError);
    PyModule_AddObject(m, "IniDbFileNotFoundError", IniDbFileNotFoundError);

    // Initialize mutexes.
    pthread_mutex_init(&monitor_mutex, NULL);
    pthread_mutex_init(&section_list_mutex, NULL);
    pthread_mutex_init(&entry_list_mutex, NULL);
}

我的理解是,口译员已经准备好进入GIL了,所以没有必要在这里获得它。请注意,代码会立即崩溃,而不会运行任何单元测试,但它会偶尔崩溃。有时它会在不崩溃的情况下执行。

所以显然只是加载我的模块足以导致这种零星的崩溃,所以我显然在这里做错了。帮助赞赏。感谢。

0 个答案:

没有答案