我正在为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(§ion_list_mutex, NULL);
pthread_mutex_init(&entry_list_mutex, NULL);
}
我的理解是,口译员已经准备好进入GIL了,所以没有必要在这里获得它。请注意,代码会立即崩溃,而不会运行任何单元测试,但它会偶尔崩溃。有时它会在不崩溃的情况下执行。
所以显然只是加载我的模块足以导致这种零星的崩溃,所以我显然在这里做错了。帮助赞赏。感谢。