我有一些代码应该是一个线程安全的python / c ++ api。我正在使用宏Py_BEGIN_ALLOW_THREADS
和Py_END_ALLOW_THREADS
,它们会扩展以创建保存线程状态并创建锁。我在方法退出之前释放锁;一次进入if
语句范围,一次进入方法范围。
为什么这不编译?它会在第二个error: _save was not declared in this scope
宏处生成错误:Py_END_ALLOW_THREADS
。
uint8_t SerialBuffer::push_msg() {
#if defined (UBUNTU)
Py_BEGIN_ALLOW_THREADS
#endif
if (_type == ARRAY) {
// array access
} else if (_type == PRIORITY_QUEUE) {
// queue access
} else {
// Placing the return statement in the preprocessor directive
// has no effect.
#if defined (UBUNTU)
Py_END_ALLOW_THREADS
#endif
return FAIL;
}
#if defined (UBUNTU)
Py_END_ALLOW_THREADS
#endif
return SUCCESS;
}
我还尝试将return
语句放在#if
指令范围内,这会产生相同的错误。但是,这有效:
uint8_t SerialBuffer::push_msg() {
#if defined (UBUNTU)
Py_BEGIN_ALLOW_THREADS
#endif
if (_type == ARRAY) {
// array access
} else if (_type == PRIORITY_QUEUE) {
// queue access
} else {
// NOTE lack of #if directive here.
// Even though if this code executes the code below will not.
// Seems like a relatively simple problem for lambda calculus, no?
return FAIL;
}
#if defined (UBUNTU)
Py_END_ALLOW_THREADS
#endif
return SUCCESS;
}
编辑:我知道第二个例子不做线程清理;然而,它编译。</ p>
EDIT2:
Py_BEGIN_ALLOW_THREADS
扩展为{ PyThreadState *_save; _save = PyEval_SaveThread();
Py_END_ALLOW_THREADS
扩展为PyEval_RestoreThread(_save); }
请注意,范围大括号前置BEGIN
并附加END
。为什么宏观扩展的逻辑选择包括范围界定?
答案 0 :(得分:4)
预处理器将宏Py_BEGIN_ALLOW_THREADS
扩展为创建名为_save
的本地对象的代码。
预处理器将宏Py_END_ALLOW_THREADS
扩展为使用_save
执行线程清理任务的代码。
如果您将Py_BEGIN_ALLOW_THREADS
放在else块中,则Py_END_ALLOW_THREADS
创建的代码无法看到本地_save
对象,因此您会收到错误消息。
在相关主题上,我建议将Py_BEGIN_ALLOW_THREADS
和Py_END_ALLOW_THREADS
放在哪里,如果第一个执行,那么第二个也是如此。如果您有数组类型或优先级队列类型,则该函数的第二个版本将不会执行Py_END_ALLOW_THREADS
的线程清理任务。
试试这个:
uint8_t SerialBuffer::push_msg() {
#if defined (UBUNTU)
Py_BEGIN_ALLOW_THREADS
#endif
uint8_t response = FAIL;
if (_type == ARRAY) {
// array access
response = SUCCESS;
} else if (_type == PRIORITY_QUEUE) {
// queue access
response = SUCCESS;
}
#if defined (UBUNTU)
Py_END_ALLOW_THREADS
#endif
return response;
}
在此版本中,默认响应为FAIL,因此您甚至不需要最后的其他部分。如果一切顺利,其他if语句只设置对SUCCESS的响应。
答案 1 :(得分:2)
来自[Python 3]: Py_BEGIN_ALLOW_THREADS(重点是我的):
此宏扩展为
{ PyThreadState *_save; _save = PyEval_SaveThread();
。请注意,它包含一个开括号; 必须与以下Py_END_ALLOW_THREADS宏匹配。请参阅上面的有关此宏的进一步讨论。
因此,编译错误的答案很明确:
预处理后,2 nd Py_END_ALLOW_THREADS 生成无效代码(#if defined (UBUNTU)
中的内容无关紧要,因为当< em> UBUNTU 已定义,并且在未启用时将始终有效):
这两个宏的常见用例也在上一页中得到了示例:
PyThreadState *_save; _save = PyEval_SaveThread(); ... Do some blocking I/O operation ... PyEval_RestoreThread(_save);
为什么采用这种方式设计(包括范围界定)? 像您一样使用时可能会失败,因为那样可能会导致难以发现错误(您的示例非常简单,但是在更复杂的片段代码中,有许多分支需要的 Py_END_ALLOW_THREADS < / em>,想象一下错过一个或两次叫它意味着什么。
为了解决您的问题,您必须将代码重新设计为: