【问题标题】:Is a C++11 mutex compatible with threads NOT created with C++11?C++11 互斥锁是否与不是用 C++11 创建的线程兼容?
【发布时间】:2013-12-25 01:16:08
【问题描述】:

我正在学习 C++11,但遇到了线程问题。我的一般问题:C++11 互斥锁是否与不是使用 C++11 标准库创建的线程兼容?

我想在使用 C++11 创建的线程和由我无法控制的第三方库创建的另一个线程之间安全地共享信息。

例如,我的应用程序使用 PortAudio,它为音频输出创建自己的线程。我不确定它是使用 pthread 还是特定于操作系统的线程库,但我知道 PortAudio 不是用 C++11 编写的。我想在 GUI 线程(使用 C++11 线程)和使用互斥锁的 PortAudio 线程之间安全地共享数据。

同样,我可以使用 C++11 互斥锁来同步 QT QThreads 和 C++11 线程吗?

【问题讨论】:

  • 呃,其他代码使用的是什么互斥锁?您不能期望使用多个不同的互斥锁来保护单个资源。必须是唯一的互斥体。
  • 目的是在不同类型的线程中使用单个互斥锁。
  • 该标准对您没有帮助,因为您使用的是特定于实现的线程。但可以肯定的是,在任何运行这些库的平台上,互斥锁都可以在任何线程上正常工作。
  • pthread 互斥锁可以与 C++ 线程一起使用,反之亦然。但标准不会告诉你。
  • @Tim 不会是 UB。这将是实现定义的行为。

标签: c++ multithreading qt c++11 pthreads


【解决方案1】:

C++11 互斥锁是否与不是使用 C++11 标准库创建的线程兼容?

C++ 标准没有将“线程”定义为由 C++ 标准库专门创建的东西。

1.10 多线程执行和数据竞争 [intro.multithread]

1 一个执行线程(也称为线程)是一个单一的流程 程序中的控制,包括初始调用 特定的顶级函数,并递归地包含每个函数 调用随后由线程执行。

所以,我认为你的问题的答案是“是”。

【讨论】:

    【解决方案2】:

    显然,C++ 标准不保证与其他系统的兼容性。 C 和 C++ 标准添加线程工具的部分原因是为了在一个线程系统上进行标准化。

    在实践中,预计 C 和 C++ 线程库被构建为与平台线程系统集成(如果有的话)。例如,在使用 pthreads 的平台上,期望在适当的地方使用 pthreads 来构建标准库线程设施(据我所知,各种原子操作没有 pthreads 接口,即标准库可能需要提供自己的同步原语)。

    标准库类通过native_handle() 方法提供对底层表示的访问。一个标准库应该实现从这些返回的内容,例如,如果提供了 pthreads 类型,那么假设这个特定的标准库将与 pthreads 很好地配合似乎是安全的。

    【讨论】:

    • 但是请注意,native_handle 不需要存在,如果它存在,它的返回类型是实现定义的。简而言之:非常不便携。
    【解决方案3】:

    C++11 标准规定互斥锁应与任何类型的“执行代理”一起使用,包括不同的线程库。以下是标准中的一些相关引用,我认为这些引用可以最终回答这个问题:

    互斥量要求

    互斥对象有助于防止数据竞争并允许 执行代理之间的数据安全同步 (30.2.5)。一个 执行代理从它成功调用一个互斥锁开始就拥有一个互斥锁 锁定功能,直到它调用解锁。

    可锁定类型的要求

    执行代理是一个实体,例如可以执行工作的线程 与其他执行代理并行。 [注:实现或 用户可以引入其他类型的代理,例如进程或 线程池任务。 —尾注]呼叫代理由以下决定 上下文,例如包含调用的调用线程,依此类推。

    【讨论】:

    • 这就是Mutex 概念的定义。也就是说,任何具有 mutex-y 接口的对象。它说并不意味着std::mutex 支持任何类型的执行代理。 (它没有)
    • @R.MartinhoFernandes 是吗? std::mutex 不适用于哪种执行代理?
    • 说真的,你能举一个具体的例子说明什么时候 std::mutex 不能按预期工作吗?我想测试一下。因为此刻我只是不相信你。 (但我愿意被说服。)
    • 尝试将它与某种绿色线程一起使用。 std::mutex 总是阻塞物理线程。它不知道任何其他类似的机制。
    【解决方案4】:

    无法想象C++11的线程实现会与平台的原生线程实现不兼容,因为任何使用C++11线程的实际程序都会调用平台库,而这些库本身可能是线程化的或make thread相关调用(例如互斥体)。

    线程的 C++11 库实现当然不必使用高级本机线程库(例如,pthreads 或 windows 线程),但它可能会,为此目的,正如已经提到的,有一个标准: :thread::native_handle() 方法来获取本地句柄。然而,即使它不使用高级本机实现,它也必须在下面使用相同的低级内核原语。

    因此,在所有可能的情况下,将 C++11 互斥锁与本地库调用创建的线程实例一起使用应该是完全安全的,反之亦然,并混合任何其他本地或 C++ 库同步调用。确实可能存在有必要这样做的情况。例如,C++11 库目前不提供线程池或读写锁(共享互斥锁)。您可能希望对使用 std::thread 启动的线程使用本机读写锁,或使用 C++ 程序中第三方库提供的众多线程池实现之一。

    唯一需要注意的是,尝试将 C++11 线程(由于上述原因,在实践中将不得不以一种或另一种方式使用内核线程)与不使用内核线程的线程库混合使用所有(例如,基于绿色线程或“用户”线程的库),可能会给您带来麻烦。

    编辑:为了支持这一点,我注意到 C++11 的第 30.3 节指出,尽管是非规范的,“这些线程 [std::thread 线程] 旨在与操作系统线程一对一地映射”。

    【讨论】:

      猜你喜欢
      • 2015-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      相关资源
      最近更新 更多