如何实现函数线程安全

时间:2017-05-31 11:15:25

标签: c++ c multithreading thread-safety

我从宏调用一个函数(返回字符串)。多个线程可以在系统中使用此宏。

例如:

#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成为线程安全????

2 个答案:

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