Skip to content

Instantly share code, notes, and snippets.

@FinalTheory
Created September 24, 2015 13:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FinalTheory/65f2da14ed1c4759cade to your computer and use it in GitHub Desktop.
Save FinalTheory/65f2da14ed1c4759cade to your computer and use it in GitHub Desktop.
C extension中发起新线程回调Python函数时未获取GIL导致core的演示代码
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")
#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);
}
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()
@FinalTheory
Copy link
Author

该示例代码在Mac OS X 10.10下编译通过,使用的是homebrew维护的Python版本。使用系统自带Python理论上也应该能够正确编译。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment