【问题标题】:Is thread::id used anywhere in the standard C++ library?thread::id 是否在标准 C++ 库中的任何地方使用?
【发布时间】:2014-09-13 16:33:05
【问题描述】:

std::thread::get_id() 为您提供了一个实现定义的值,它唯一地标识给定线程,但对我来说有趣的是有一个专用类型,thread::id,这个类型在标准库中的任何地方都使用吗?

thread::id 在您知道的某处或任何界面中使用? AFAIK 这种类型在任何地方都没有使用,因此它目前看起来毫无用处。

【问题讨论】:

  • 不在标准库中使用并不会使其无用。您可以在自己的代码中使用它,不是吗? :)
  • @MagnusHoff 好的,但是此时您可以将任何整数类型用于std::thread::get_id() 的结果,为什么您将专用类型用于实际上不需要新类型的东西并且您也没有在标准库的任何其他部分使用上述类型?
  • 我敢打赌,它是允许实现根据平台使用的任何内容来选择类型。 32位整数? 64位整数?指针?所有这些都符合当前标准:)
  • “它是定义的实现,所以它可以是任何东西。”
  • @user2485710 ... 所以它可以例如用作线程容器的键。这比您自己生成随机 ID 或为您使用的每个线程命名要实用得多。

标签: c++ multithreading c++11 c++14


【解决方案1】:

此类用户定义类型的目的是为实现者提供便利。

在许多情况下,您将在现有代码库、操作系统系统等之上实现 C++ 线程。这些可能有不同类型的线程标识。

使用该类型,C++ std 实现更有可能直接公开底层线程标识值,或者只进行最少的修改。

在许多情况下,从客户端了解您所在的线程非常有用,而在没有系统 ID 的情况下实现它很复杂。

std::thread::id 可以排序、比较(以完全有序的方式,具有合理的相等性)和std::hashed,所有这些都对std 库很有用。它们可以被复制(简单地)并在没有参数的情况下构造(对于表示没有线程的 id)。它们可以通过ostream << 转换为字符串,唯一的保证是生成的字符串永远不会相同,除了两个== id。

除此之外对它们的任何操作都是未定义的。但是,一个实现可以使thread_id 基本上是一个指针,或者数组中的无符号整数索引,或者许多不同的底层实现之一。然而,访问此类信息的实现完全依赖于实现。

【讨论】:

  • 例如,如果我在 linux 下,我在 C 中混合了一些 Pthread 代码和一些标准 C++11 代码,我应该得到一个一致且可预测的线程枚举,因为底层线程平台是还是 pthread ?
  • 我想补充一点,thread::id 是一个内部类,用于存储保证每个线程都是唯一的 ID,获取其值的唯一方法是使用ostream & operator<<以文本形式获取它。
  • 你也可以通过std::hash获取整型值。
  • @JensÅkerblom 该哈希值与实际值无关(好吧,对于文本表示也是如此 - “未指定”)。但不同之处在于哈希不必是唯一的,而文本表示则必须是唯一的。
  • @user2485710 没有这样的保证,抱歉:这是为了方便库开发人员。但是,您可以检查您的特定实现并进行检查。并且不通过指定的方法检查它是未定义的行为。
【解决方案2】:

thread::id 是否在标准 C++ 库中的任何地方使用?

不,thread::id 没有在标准 C++ 库的接口中使用。

它可能用于递归互斥锁之一的实现,但这将是一个实现细节。我不知道当前是否有任何实现使用它。

AFAIK 这种类型无处使用,因此看起来毫无用处 目前。

以下是 std::library 中的一些其他类型,根据这个定义是“无用的”:

  • 列表
  • 设置
  • 多组
  • 地图
  • 多地图
  • unordered_set
  • unordered_multimap
  • 数组
  • 原子的
  • 位集
  • 复杂
  • 条件变量
  • condition_variable_any
  • forward_list
  • fstream
  • reverse_iterator
  • move_iterator
  • 互斥体
  • 队列
  • 堆栈
  • 正则表达式
  • 线程

这不是一个详尽的列表。


有点不情愿的更新

我:

您的问题是:thread::id 的激励用例是什么?

用户2485710:

是的,听起来不错,也许是对标准库的特别关注。

thread::id 有时用于将线程映射到属性,反之亦然。例如,可以通过在std::map 中将std::stringstd::thread::id 相关联来实现“命名线程”。当一个执行线程被记录、抛出异常或有一些值得注意的事件时,可以查找线程的名称来为日志、错误消息等创建一条消息,以便提供更好的上下文。例如,线程可能具有暗示性名称,例如:“数据库服务器”或“表更新器”。

thread::idthread 更方便用于此应用程序,因为在其他地方通常需要 thread 来控制加入。

thread::id 的另一个用途是检测当前执行函数的线程是否与执行相同函数的最后一个线程相同。我已经看到在recursive_mutex::lock() 的实现中使用了这种技术。例如,如果互斥锁被锁定并且this_thread::get_id() == stored_id,则增加锁定计数。

至于“专注于标准 C++ 库”,我真的不知道这是什么意思。如果它的意思是:“在界面中使用”,那么这个问题已经在这个答案的前面得到了回答,在其他答案中:

不,thread::id 没有在标准 C++ 库的接口中使用。

std::lib 中有很多很多类型不是 std::lib 其他部分的 API 的一部分。 thread::id 未标准化,因为库的其他部分的 API 需要它。它之所以被标准化是因为 std::thread 正在被标准化,而 thread::idstd::thread 库的自然组成部分,并且因为它对上述用例很有用。

threadthread::id 之间的主要区别在于thread 维护执行线程的唯一所有权。因此thread 是只移动类型。这与unique_ptr 非常相似。 join() 只能使用一个std::thread。相反,thread::id 只是thread 的“名称”。名称是可复制和可比较的。它们不用于所有权,仅用于识别。

这种关注点分离(加入特权与标识)在支持仅移动和可复制类型的语言中更加明显。

【讨论】:

  • 相当肯定 deque 被“使用”为几个容器适配器的默认模板参数(并且 cout 不是类型):)
  • @T.C.:很公平。列表减少。
  • hash 的事情正在失控;是的,我知道即使在发布之前,hash() 就是这种类型的成员函数,很容易识别出这种功能的存在,我的观点更多的是关于 thread::id 作为一种类型。如果标准将实现在函数接口中给出thread::idstd::packaged_task 的东西,那将不是很好,我不知道......,将任务从你所在的线程移动到你的目标线程?或多或少就像一个工作窃取队列。这将是一个使用 thread::id 的函数来做一些有用的事情。
  • 我的意思是,答案都集中在这种类型可以做什么,而不是这种类型有效地用于什么。是的,我可以使用hash 为容器构建元素,但我基本上可以hash 任何东西,所以这个 hash 的东西 它并不是真正的thread::id 特定的,它并没有真正专注于我正在寻找的东西对于我的问题。
  • @user2485710:那你的问题是什么?还是您的“问题”只是对 std::lib 现有设计的抱怨?
【解决方案3】:

AFAIK 这种类型在任何地方都没有使用,因此它目前看起来毫无用处。

thread::id 实现了关系运算符和散列支持。这允许您(用户)将它们作为关联和无序容器中的键。

【讨论】:

  • 是的......但这并不是很有趣,我的意思是我可以用几乎所有东西,任何对象,我几乎可以散列任何东西。这并不是您可以专门针对任务和线程的场景。
  • 任何其他对象都不能保证它代表一个执行线程。你会使用哪个其他对象?
猜你喜欢
  • 2021-04-13
  • 2011-01-23
  • 2017-03-19
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 2021-10-27
相关资源
最近更新 更多