是va_start(等)可重入吗? [英] Is va_start (etc.) reentrant?
问题描述
在对具有悠久历史的类进行编辑时,我被建筑师的一种特殊习惯阻碍了他的va_start - > va_end序列在互斥体中。该添加的更改日志(这是在大约15年前,但没有修订)注意到,这是因为va_start等。所有不可重入。
我不知道va_start有任何这样的问题,因为我一直认为它只是一个堆栈指针数学的宏。这里有我不知道的东西吗?如果有副作用,我不想更改此代码。
具体来说,这个函数看起来很像这样:
void write(const char * format,...)
{
mutex.Lock();
va_list args;
va_start(args,format);
_write(format,args);
va_end(args);
mutex.Unlock();
}
这是从多个线程调用的。
foo()
调用 bar()
va_start
),答案是很好 - 只要 va_list
实例不一样。标准说,
不会调用va_start和va_copy宏来重新初始化ap,而不会干扰对同一个ap的va_end宏的调用。
所以,只要不同的 va_list
如果通过可重入意味着线程安全(我假设你是,因为互斥体涉及),你需要查看实现的细节。由于C标准没有谈到多线程,这个问题是真的由实现来确保。我可以想象,在一些奇怪的或小的架构上,可能很难使 va_start
线程安全,但我想如果你在一个现代主流平台上工作可能没有问题。
在更多的主流平台上,只要不同的 va_list
va_start
宏你应该没有问题,多个线程通过'same' va_start
。因为 va_list
参数通常在栈上(因此不同的线程将有不同的实例),你通常处理 va_list的不同实例
我认为在您的示例中,互斥体对于varargs的使用是不必要的。但是,如果 write()
,那么对于 write()
调用序列化,你没有多个 write()
线程拧紧彼此的输出。
While making an edit to a class with a long history, I was stymied by a particular habit of the architect of wrapping his va_start -> va_end sequence in a mutex. The changelog for that addition (which was made some 15 years ago, and not revised since) noted that it was because va_start et. all was not reentrant.
I was not aware of any such issues with va_start, as I always thought it was just a macro for some stack-pointer math. Is there something here I'm not aware of? I don't want to change this code if there will be side-effects.
Specifically, the function in question looks a lot like this:
void write(const char *format, ...)
{
mutex.Lock();
va_list args;
va_start(args, format);
_write(format, args);
va_end(args);
mutex.Unlock();
}
This is called from multiple threads.
As far as being serially-reentrant (ie., if foo()
uses va_start
is it safe for foo()
to call bar()
which also uses va_start
), the answer is that's fine - as long as the va_list
instance isn't the same. The standard says,
Neither the va_start nor va_copy macro shall be invoked to reinitialize ap without an intervening invocation of the va_end macro for the same ap.
So, you're OK as long as a different va_list
(referred to above as ap
) is used.
If by reentrant you mean thread-safe (which I assume you are, since mutexes are involved), you'll need to look to the implementation for the specifics. Since the C standard doesn't talk about multi-threading, this issue is really up to the implementation to ensure. I could imagine that it might be difficult to make va_start
thread-safe on some oddball or small architectures, but I think if you're working on a modern mainstream platform you're likely to have no problems.
On the more mainstream platforms as long as a different va_list
argument is being passed to the va_start
macro you should have no problem with multiple threads passing through the 'same' va_start
. And since the va_list
argument is typically on the stack (and therefore different threads will have different instances) you're generally dealing with different instances of the va_list
.
I think that in your example, the mutexes are unnecessary for the varargs use. However, if the write()
, it certainly would make sense for a write()
call to be serialized so that you don't have multiple write()
threads screwing up each other's output.
这篇关于是va_start(等)可重入吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!