sqlite3_mutex_enter()上的访问冲突。为什么?

时间:2014-06-16 22:54:38

标签: python c python-3.x sqlite

我在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);
  }
}

很抱歉有很多片段,但我对这个问题一无所知。

提前致谢。

2 个答案:

答案 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);

”来理解我的意思。