我在Python3 / C模块中使用sqlite-amalgamation-3080500。
我的python模块创建了一些表,然后使用 PyCapsule 将sqlite3的句柄返回到python环境。
所以,在第二个模块中,我尝试使用相同的sqlite3的句柄创建更多表。但我的计划正在破产。我在sqlite3_mutex_enter()中遇到了“访问冲突错误” - 这是由sqlite3_prepare_v2()调用的。
python.exe中0x00000000处的第一次机会异常:0xC0000005:Access 违规执行位置0x00000000。处理未处理的异常 python.exe中的0x7531C9F1:0xC0000005:执行访问冲突 位置0x00000000。
它真的是线程安全的吗?我想我可以这样做。我过去已经做过,但我在Mac上使用XCode。现在我想在MSVC 2013上做同样的事情。
Bellow是我运行查询的代码:
bool register_run(register_db_t *pReg, const char *query)
{
int ret, len;
sqlite3_stmt *stmt;
const char *err;
stmt = NULL;
len = (int)strlen(query);
ret = sqlite3_prepare_v2(pReg->pDb, query, len, &stmt, NULL);
if (ret != SQLITE_OK) {
err = sqlite3_errmsg(pReg->pDb);
fprintf(stderr, "sqlite3_prepare_v2 error: %s\n%s\n",
err, query);
return false;
}
ret = register_run_stmt(pReg, query, stmt);
sqlite3_finalize(stmt);
return ret;
}
这就是我导出句柄以在我的第二个C /模块中使用它的方法:
// Register's getattro
static PyObject* Register_getattro(RegisterObject *self, PyObject *name)
{
// ...
} else if (PyUnicode_CompareWithASCIIString(name, "handle") == 0) {
register_db_t *handle = self->db;
return PyCapsule_New(handle, NULL, NULL);
}
return PyObject_GenericGetAttr((PyObject *)self, name);
}
这是python代码粘合件:
import registermodule, loggermodule
reg = registermodule.Register("mydata.db")
loggermodule.set_register(reg.handle)
我如何使用第二个模块上的句柄:
static PyObject* loggerm_set_register(PyObject *self, PyObject *args)
{
register_db_t *pReg;
PyObject *capsule;
if (!PyArg_ParseTuple(args, "O:set_register", &capsule)) {
return NULL;
}
if (!PyCapsule_CheckExact(capsule)) {
PyErr_SetString(PyExc_ValueError,
"The object isn't a valid pointer.");
return NULL;
}
pReg = PyCapsule_GetPointer(capsule, NULL);
if (!logger_set_register(pReg)) {
PyErr_SetString(PyExc_SystemError,
"Could not set the pointer as register.");
return NULL;
}
Py_RETURN_NONE;
}
最后是破坏的例程:
bool logger_set_register(register_db_t *pReg)
{
char *query = "CREATE TABLE IF NOT EXISTS tab_logger ("
"date NUMERIC,"
"level TEXT,"
"file TEXT,"
"function TEXT,"
"line INTEGER,"
"message TEXT)";
g_pReg = pReg;
return register_run(g_pReg, query);
}
sqlite3的例程正在破坏所有:
SQLITE_API void sqlite3_mutex_enter(sqlite3_mutex *p){
if( p ){
sqlite3GlobalConfig.mutex.xMutexEnter(p);
}
}
很抱歉有很多片段,但我对这个问题一无所知。
提前致谢。
答案 0 :(得分:2)
我不知道为什么,但是Windows上的Python C模块之间的全局变量是不一样的。尽管我之前有过这样的经历,但它并没有出现在Mac OS上。
在Windows中,python模块是DLL,因此它们不共享相同的全局堆栈。
我发现sqlite3Config.mutex对我的第二个Python C模块是NULL。它导致访问冲突错误。但是sqlite3Config.mutex是一个全局变量,这个东西应该由前一个模块启动。
现在,知道这一点,我解决了调用此函数的问题:
sqlite3_initialize();
一切正常!
答案 1 :(得分:0)
不确定您的问题是否与 sqlite3_initialize() 直接相关; 因为 sqlite3_initialize();在 sqlite3_open_v2 期间至少自动调用一次。
我建议在 sqlite3_open_v2 期间挖掘 SQLITE_OPEN_FULLMUTEX 选项的缺失。 建议始终设置此选项。使用 Mutex 的代价非常低,尤其是考虑到 Python 添加的所有开销。 在单线程中可以忽略不计,在多线程中强制(几乎)。我什至不明白为什么它仍然是一个选择。应该一直在 所以安全总比后悔好。我不知道使用的真正缺点。 SQLite 是“精简版”
顺便说一句,sqlite3Config.mutex 为 NULL 是合法的。 这应该仅由检查此条件的 SQLite 使用, 在 sqlite3.c 中搜索“
<块引用>sqlite3_mutex_enter(db->mutex);
”来理解我的意思。