boost :: format()似乎不是线程安全的,因为std :: ctype <char> :: narrow()不是线程安全的

时间:2018-07-27 22:56:16

标签: c++ multithreading boost

我遇到了在多个线程中使用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;
  }

1 个答案:

答案 0 :(得分:1)

_M_narrow的定义是:

mutable char _M_narrow[1 + static_cast<unsigned char>(-1)];

并行阅读/写入实际上实际上通常是一种危险,但是就我所知,在这种特殊情况下,这样做很好。 (如果我错了,请有人纠正我)

  • 数据结构是一个数组,如果写入(与例如std :: map相对),则不会在结构上失效
  • 元素本身是char。编写char是所有主要处理器(与intlongdouble相对)上的原子操作
  • 我看到的唯一竞争条件是检查缓存是否为空的if与对缓存的写操作之间。但是,如果发生竞争,两个线程将并行评估do_narrow,然后将相同的结果写入缓存。

我认为这涵盖了所有危险情况,这意味着该操作实际上是线程安全的,不需要锁定。

这种类型的实现的唯一问题是clang的线程清理器讨厌,即使它是安全的,也总是将其报告为潜在危害。