【问题标题】:c++11 std::hash function object classes thread safetyc++11 std::hash函数对象类线程安全
【发布时间】:2016-03-26 22:44:23
【问题描述】:

在 c++11 中,<functional> 线程中声明的哈希函数类对象是否安全?例如,从多个线程调用此函数是否安全?

size_t hash1(const std::string& s) {
    std::hash<std::string> str_hash;
    return str_hash(s); 
}

或者,如果有一个全局对象std::hash&lt;std::string&gt; str_hash_global;,那么从多个线程调用第二个函数是否安全?

size_t hash2(const std::string& s) {
    return str_hash_global(s); 
}

【问题讨论】:

  • 除其他注意事项外,请确保在计算其哈希值时字符串本身没有被同时修改。

标签: c++ c++11 thread-safety


【解决方案1】:

标准库承诺,如果您在标准库对象上调用const-qualified 成员函数,标准库代码不会导致数据竞争(参见 [res.on. data.races])。

标准模板std::hash,以及它所有允许的特化,以及满足Hash 要求([hash.requirements])的任何用户提供的函子必须有一个const-qualified call operator由于要求,因此使用库提供的std::hash 专业化不应引起竞争。此外,由于 [namespace.std],程序提供的专业化必须满足相同的要求。

最后,我想您通常会通过递归调用const 调用来使用无竞争保证:如果您的多个线程同时在映射中查找值,它们必须使用映射的const 接口来调用上面的库规则,但是映射只能使用哈希器的常量值(或私有副本),因此它本身只能执行无竞争的哈希计算。在这一点上,是否存在一个活泼的非常量调用运算符是不确定的。

【讨论】:

  • must have a const-qualified call operator due to the requirements 标准的哪个部分需要它?我正在寻找这样的东西,但找不到。有“返回的值应仅取决于参数k 在程序期间”,但这并没有直接说“operator() 必须是 const-qualified”
  • @IgorTandetnik:它说“h 是一个(可能是const)值”。
  • 啊,是的,确实如此。 “h 是一个类型的值(可能是 const)H”,准确地说。我想这仍然没有严格排除提供operator() 的两个重载的类,一个 const 和一个非常量(尽管目前尚不清楚为什么有人会想要这样做)。
  • @IgorTandetnik:啊,是的,那将是邪恶的:-S
  • @hovo:是的,应该这样做。或 C++17 中的 return std::as_const(str_hash)(s);
【解决方案2】:

此处适用与所有 std::lib 类型相同的“线程安全”规则。

第一个版本保证是线程安全的,因为线程之间没有共享变量。

如果被调用的operator()const,则保证第二个不会发生任何数据争用。除了(必需的)const 之外,实现是否提供hash&lt;T&gt;::operator() 的(可能是非线程安全的)非常量重载是未指定的。如果您的global_str_hash 是 const,或者您在使用它之前将其转换为 const,那么您保证将使用 const operator()

没有理由做第二个版本,这很傻,但实际上它应该是安全的,因为没有标准库实现可能提供hash::operator() 的活泼的非常量重载,它们只会提供一个 const重载,必须是线程安全的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-03
    • 2015-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2014-10-26
    • 2010-11-24
    相关资源
    最近更新 更多