我遇到了在多个线程中使用boost :: format()似乎存在问题的情况。 boost格式库使用boost解析库,该库使用在/usr/include/c++/4.8/bits/locale_facets.h中定义的函数std :: ctype :: narrow()(我使用的是G ++版本4.8)。
narrow()函数不是很无害。实例变量_M_narrow是一个缓存。我发现在各个线程中,该缓存是同时写入和读取的。必须锁定线程以使用boost :: format似乎很愚蠢,可以避免使用boost :: format,这使我认为我一定缺少某些东西。还有人对这个问题有更多的见识吗?
/**
* @brief Narrow char
*
* This function converts the char to char using the simplest
* reasonable transformation. If the conversion fails, dfault is
* returned instead. For an underived ctype<char> facet, @a c
* will be returned unchanged.
*
* This function works as if it returns ctype<char>::do_narrow(c).
* do_narrow() must always return the same result for the same input.
*
* Note: this is not what you want for codepage conversions. See
* codecvt for that.
*
* @param __c The char to convert.
* @param __dfault Char to return if conversion fails.
* @return The converted character.
*/
char
narrow(char_type __c, char __dfault) const
{
if (_M_narrow[static_cast<unsigned char>(__c)])
return _M_narrow[static_cast<unsigned char>(__c)];
const char __t = do_narrow(__c, __dfault);
if (__t != __dfault)
_M_narrow[static_cast<unsigned char>(__c)] = __t;
return __t;
}
答案 0 :(得分:1)
_M_narrow的定义是:
mutable char _M_narrow[1 + static_cast<unsigned char>(-1)];
并行阅读/写入实际上实际上通常是一种危险,但是就我所知,在这种特殊情况下,这样做很好。 (如果我错了,请有人纠正我)
char
。编写char
是所有主要处理器(与int
,long
或double
相对)上的原子操作if
与对缓存的写操作之间。但是,如果发生竞争,两个线程将并行评估do_narrow
,然后将相同的结果写入缓存。 我认为这涵盖了所有危险情况,这意味着该操作实际上是线程安全的,不需要锁定。
这种类型的实现的唯一问题是clang的线程清理器讨厌,即使它是安全的,也总是将其报告为潜在危害。