当前位置:  开发笔记 > 编程语言 > 正文

使用gcc 4.3是std :: string thead-safe吗?

如何解决《使用gcc4.3是std::stringthead-safe吗?》经验,为你挑选了2个好方法。

我正在开发一个在Linux上运行的多线程程序(用G ++ 4.3编译),如果你搜索一下,你会发现很多关于std :: string与GCC不是线程安全的可怕故事.这可能是因为它在内部使用了写入时复制,这会对像Helgrind这样的工具造成严重破坏.

我做了一个小程序,将一个字符串复制到另一个字符串,如果你检查两个字符串,它们都共享相同的内部_M_p指针.当一个字符串被修改时,指针会发生变化,因此写入时复制的东西工作正常.

我担心的是,如果我在两个线程之间共享一个字符串(例如将它作为一个对象传递给两个线程之间的线程安全数据队列)会发生什么.我已经尝试使用'-pthread'选项进行编译,但这似乎没有太大区别.所以我的问题:

有没有办法强制std :: string是线程安全的?我不介意是否禁用了写时复制行为来实现这一点.

别人怎么解决这个问题?还是我是偏执狂?

我似乎无法找到明确的答案,所以我希望你们能帮助我..

编辑:

哇,在这么短的时间内,这是很多答案.谢谢!当我想禁用COW时,我肯定会使用Jack的解决方案.但现在主要问题变成:我真的必须禁用COW吗?或者COW线程的"簿记"是否安全?我目前正在浏览libstdc ++源代码,但这需要相当长的时间来弄清楚......

编辑2

好了,浏览了libstdc ++源代码,我在libstd ++中找到了类似的东西--v3/include/bits/basic_string.h:

  _CharT*
   _M_refcopy() throw()
   {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
     if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
     return _M_refdata();
   }  // XXX MT

因此,参考计数器肯定有一些关于原子变化的东西......

结论

我将sellibitze的评论标记为答案,因为我认为我们已经得出结论,这个领域目前尚未解决.为了规避COW的行为,我建议Jack Lloyd回答.谢谢大家的有趣讨论!



1> sellibitze..:

线程还不是标准的一部分.但是我认为现在没有任何供应商可以在不使用std :: string线程安全的情况下逃脱.注意:"线程安全"有不同的定义,我的可能与您的不同.当然,即使您不需要它,默认情况下保护像std :: vector这样的容器进行并发访问也没什么意义.这将违背"不要为不使用的东西买单"的C++精神.如果用户想要在不同线程之间共享对象,则应始终负责同步.这里的问题是,从用户的角度来看,即使"函数应用于不同的对象",库组件是否使用和共享一些可能导致数据竞争的隐藏数据结构.

C++ 0x草案(N2960)包含"数据竞争规避"部分,它基本上表示库组件可以访问对用户隐藏的共享数据,当且仅当它激活地避免可能的数据竞争时.听起来std :: basic_string的copy-on-write实现必须与其他实现一样安全,多线程,其中内部数据永远不会在不同的字符串实例之间共享.

我不是100%肯定libstdc ++是否已经处理它.我认为确实如此.当然,请查看文档



2> Jack Lloyd..:

如果您不介意禁用写时复制,这可能是最好的做法.std :: string的COW只有在知道它正在复制另一个std :: string时才有效,所以你可以让它总是分配一个新的内存块并制作一个实际的副本.例如这段代码:

#include 
#include 

int main()
   {
   std::string orig = "I'm the original!";
   std::string copy_cow = orig;
   std::string copy_mem = orig.c_str();
   std::printf("%p %p %p\n", orig.data(),
                             copy_cow.data(),
                             copy_mem.data());
   }

将显示第二个副本(使用c_str)阻止COW.(因为std :: string只看到一个简单的const char*,并且不知道它来自哪里或它的生命周期是什么,所以它必须创建一个新的私有副本).


小警告:如果orig包含嵌入的空值,则分配给c_str()的结果将截断字符串.使用带有const char*和size_type的assign方法(或构造函数),并将"orig.data()"和"orig.size()"传递给它会更安全.
推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有