C ++ macro in case if statement does not compile
I have some code that needs to be thread safe python / c ++ api. I use macros Py_BEGIN_ALLOW_THREADS
and Py_END_ALLOW_THREADS
, which extend to create a thread save state and create a lock. I release the lock before the method exits; once inside the scope if
and once in the scope of the method.
Why doesn't it compile? It generates an error: error: _save was not declared in this scope
in the second macro 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;
}
I also tried to put the statement return
inside the scope #if
and it throws the same error. However, this works:
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;
}
Edit: I know that the second example doesn't clean up streams; however, it compiles.
Edit2:
Py_BEGIN_ALLOW_THREADS
expands to{ PyThreadState *_save; _save = PyEval_SaveThread();
Py_END_ALLOW_THREADS
expands to PyEval_RestoreThread(_save); }
SPECIFY curly braces BEGIN
appending and appending END
. Why does the logical choice for expanding a macro include scoping?
source to share
The preprocessor expands the macro Py_BEGIN_ALLOW_THREADS
into code that creates a local named object _save
.
The preprocessor extends the macro Py_END_ALLOW_THREADS
into code that it uses _save
to perform stream cleanup tasks.
If you put Py_BEGIN_ALLOW_THREADS
inside an else block, the generated code Py_END_ALLOW_THREADS
cannot see the local object _save
, so you get an error.
In the relevant topic, I recommend placing Py_BEGIN_ALLOW_THREADS
and Py_END_ALLOW_THREADS
, where, if the first is executed, then the second. The second version of the function will not perform thread cleanup tasks for Py_END_ALLOW_THREADS
if you have an array type or a priority queue type.
Try the following:
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;
}
In this version, the default answer is FAIL, so you don't even need the last section section. The other if statements only set the answer to SUCCESS if all goes well.
source to share