我从宏调用一个函数(返回字符串)。多个线程可以在系统中使用此宏。
#define LOG(app,str) printf("App =%d\n, Ouptut String = %s\n",app,
foo str );
char* foo(const char *fmt, ...) {
static char logmsg[200]; //Maximum log Msg String length
va_list args;
va_start(args, fmt);
vsprintf(logmsg,fmt, args);
va_end(args);
return logmsg;
}
LOG Macro Usage : LOG(15,("Msg=%s\n",strvariable));
现在在我的情况下,函数foo()
不是线程安全的。如何在没有使用互斥锁的情况下如何使这个宏/ func成为线程安全????
答案 0 :(得分:2)
您正在寻求保护内部缓冲区。显然,您无法在函数中应用互斥锁或原子锁,因为该缓冲区在函数外部使用。
忽略设计和实现中的明显缺陷(没有保护的固定长度缓冲等等),有一种方法可以保护缓冲区。
那就是使它成为thread_local:
char* foo(const char *fmt, ...) {
// thread_local
thread_local static char logmsg[200]; //Maximum log Msg String length
va_list args;
va_start(args, fmt);
std::vsprintf(logmsg,fmt, args);
va_end(args);
return logmsg;
}
只要你没有在线程之间编组返回的指针,你就会很好。
请注意,thread_local是一个c ++ 11特性,而且在编译iOS时,apple编译器仍然没有实现它。该废话的解决方法是boost::thread_specific_ptr
。
答案 1 :(得分:1)
这是纯C答案,它产生一个完全可供任何线程使用的字符串,不依赖于下次使用时会被覆盖的静态缓冲区,并且不会冒缓冲区溢出的风险:
char *foo( const char *fmt, ... )
{
// start with what's likely enough memory
char local_buffer[ 128 ];
va_list args;
va_start( args, fmt );
int bytes_needed = vsnprintf( local_buffer, sizeof( local_buffer ), fmt, args );
va_end( args );
// if the string fit, duplicate the string dynamically and return
if ( bytes_needed < sizeof( local_buffer )
{
return( strdup( local_buffer );
}
// didn't fit, but we do know how long it needs to be
char *buffer = malloc( bytes_needed + 1 );
if ( !buffer )
{
return( NULL );
}
// can't safely reuse args
va_list args2;
va_start( args2, fmt );
vsnprintf( buffer, bytes_needed, fmt, args2 );
va_end( args2 );
return( buffer );
}