Created
September 24, 2015 13:24
-
-
Save FinalTheory/65f2da14ed1c4759cade to your computer and use it in GitHub Desktop.
C extension中发起新线程回调Python函数时未获取GIL导致core的演示代码
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.3) | |
project(demo) | |
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2") | |
set(SOURCE_FILES demo.c) | |
# if you could not build successfully or error occured when importing nids | |
# try to replace here with your real python version | |
set(PYVER "2.7.10_2") | |
string(SUBSTRING ${PYVER} 0 3 PYVER_2) | |
set(HOMEBREW_PY /usr/local/Cellar/python/${PYVER}/Frameworks/Python.framework/Versions/${PYVER_2}) | |
# first try to find hombrew version of Python.h | |
find_path(HOME_BREW_PYHDR Python.h | |
PATHS ${HOMEBREW_PY}/include/python${PYVER_2} | |
NO_DEFAULT_PATH | |
) | |
# if not found, use system version | |
find_path(HOME_BREW_PYHDR Python.h) | |
include_directories( | |
BEFORE SYSTEM ${HOME_BREW_PYHDR} | |
) | |
# first try to find hombrew version of libpython | |
find_library(HOMEBREW_PYLIB | |
python${PYVER_2} | |
PATHS ${HOMEBREW_PY}/lib | |
NO_DEFAULT_PATH | |
) | |
# if not found, use system version | |
find_library(HOMEBREW_PYLIB python${PYVER_2}) | |
add_library(demo SHARED ${SOURCE_FILES}) | |
target_link_libraries(demo ${HOMEBREW_PYLIB}) | |
set_target_properties(demo PROPERTIES PREFIX "" SUFFIX ".so") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Python.h> | |
#include <pthread.h> | |
static PyObject *callback_func = NULL; | |
void *new_thread(void *args) { | |
// 每隔10ms调用一次回调函数 | |
PyObject *ret = NULL; | |
while (1) { | |
usleep(10 * 1000); | |
// 注意:如果注释掉PyGILState_Ensure和PyGILState_Release | |
// 重新编译后运行test.py,就会导致core | |
PyGILState_STATE state = PyGILState_Ensure(); | |
PyObject_CallFunction(callback_func, "O", Py_None); | |
PyGILState_Release(state); | |
} | |
} | |
static PyObject *set_callback(PyObject *self, PyObject *args) { | |
// 注册回调函数 | |
PyObject *pyFunc = NULL; | |
if (!PyArg_ParseTuple(args, "O", &pyFunc)) { | |
return NULL; | |
} | |
callback_func = pyFunc; | |
Py_RETURN_NONE; | |
} | |
static PyObject *auto_callback(PyObject *self, PyObject *args) { | |
// 发起一个后台线程来自动调用回调函数 | |
pthread_t mutex; | |
pthread_create(&mutex, NULL, new_thread, NULL); | |
pthread_detach(mutex); | |
Py_RETURN_NONE; | |
} | |
static PyMethodDef DemoModuleMethods[] = { | |
{ | |
"auto_callback", | |
auto_callback, | |
METH_VARARGS, | |
"" | |
}, | |
{ | |
"set_callback", | |
set_callback, | |
METH_VARARGS, | |
"" | |
}, | |
{NULL, NULL, 0, NULL} | |
}; | |
PyMODINIT_FUNC initdemo(void) { | |
PyEval_InitThreads(); | |
(void)Py_InitModule("demo", DemoModuleMethods); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import demo | |
import ctypes | |
from time import sleep | |
from threading import Thread | |
def call_back_func(obj): | |
print "called in new thread" | |
def python_thread_func(): | |
print "called in python thread" | |
if __name__ == '__main__': | |
# 设置回调函数 | |
demo.set_callback(call_back_func) | |
# 调用以后台创建线程(非阻塞) | |
demo.auto_callback() | |
# 主线程继续执行 | |
while True: | |
sleep(0.01) | |
python_thread_func() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
该示例代码在Mac OS X 10.10下编译通过,使用的是homebrew维护的Python版本。使用系统自带Python理论上也应该能够正确编译。