asio隐式链和数据同步

2023-12-01

当我阅读asio源代码时,我很好奇asio是如何在线程之间同步数据的,甚至是隐式链的制作。这些是 asio 中的代码:

io_service::运行

 mutex::scoped_lock lock(mutex_);

  std::size_t n = 0;
  for (; do_run_one(lock, this_thread, ec); lock.lock())
    if (n != (std::numeric_limits<std::size_t>::max)())
      ++n;
  return n;

io_service::do_run_one

 while (!stopped_)
  {
    if (!op_queue_.empty())
    {
      // Prepare to execute first handler from queue.
      operation* o = op_queue_.front();
      op_queue_.pop();
      bool more_handlers = (!op_queue_.empty());

      if (o == &task_operation_)
      {
        task_interrupted_ = more_handlers;

        if (more_handlers && !one_thread_)
        {
          if (!wake_one_idle_thread_and_unlock(lock))
            lock.unlock();
        }
        else
          lock.unlock();

        task_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Run the task. May throw an exception. Only block if the operation
        // queue is empty and we're not polling, otherwise we want to return
        // as soon as possible.
        task_->run(!more_handlers, this_thread.private_op_queue);
      }
      else
      {
        std::size_t task_result = o->task_result_;

        if (more_handlers && !one_thread_)
          wake_one_thread_and_unlock(lock);
        else
          lock.unlock();

        // Ensure the count of outstanding work is decremented on block exit.
        work_cleanup on_exit = { this, &lock, &this_thread };
        (void)on_exit;

        // Complete the operation. May throw an exception. Deletes the object.
        o->complete(*this, ec, task_result);

        return 1;
      }
    }

在其do_run_one中,互斥锁的解锁都是在执行处理程序之前。如果存在隐式链,则handler不会并发执行,但问题是:线程A运行一个修改数据的handler,而线程B运行下一个读取线程A已修改数据的handler。没有互斥锁的保护,线程B如何看到线程A对数据所做的更改?在处理程序执行之前解锁互斥体不会在访问处理程序访问的数据的线程之间建立发生之前的关系。 当我更进一步时,处理程序执行使用一个名为 fenced_block 的东西:

 completion_handler* h(static_cast<completion_handler*>(base));
    ptr p = { boost::addressof(h->handler_), h, h };

    BOOST_ASIO_HANDLER_COMPLETION((h));

    // Make a copy of the handler so that the memory can be deallocated before
    // the upcall is made. Even if we're not about to make an upcall, a
    // sub-object of the handler may be the true owner of the memory associated
    // with the handler. Consequently, a local copy of the handler is required
    // to ensure that any owning sub-object remains valid until after we have
    // deallocated the memory here.
    Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_));
    p.h = boost::addressof(handler);
    p.reset();

    // Make the upcall if required.
    if (owner)
    {
      fenced_block b(fenced_block::half);
      BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
      boost_asio_handler_invoke_helpers::invoke(handler, handler);
      BOOST_ASIO_HANDLER_INVOCATION_END;
    }

这是什么?我知道fence似乎是C++11支持的同步原语,但这个fence完全是由asio自己编写的。这个fenced_block有助于完成数据同步的工作吗?

UPDATED

在我谷歌和阅读之后this and this,asio确实使用内存栅栏原语来同步线程中的数据,这比解锁更快,直到处理程序执行完成(x86 上的速度差异)。事实上,Java 易失性关键字是通过在写入变量之后和读取变量之前插入内存屏障来实现发生之前关系的。

如果有人可以简单地描述 asio 内存栅栏实现或添加我错过或误解的内容,我会接受它。


在操作调用用户处理程序之前,Boost.Asio 使用记忆栅栏提供适当的内存重新排序,而不强制处理程序执行的相互执行。因此,线程 B 将观察线程 A 上下文中发生的内存更改。

C++03 没有指定有关多线程执行的内存可见性要求。然而,C++11 在第 1.10 节“多线程执行和数据竞争”以及“原子操作”和“线程支持库”部分中定义了这些要求。 Boost 和 C++11 互斥体确实执行适当的内存重新排序。对于其他实现,值得检查互斥体库的文档以验证内存重新排序是否发生。

Boost.Asio 内存栅栏是一个实现细节,因此总是会发生变化。 Boost.Asio 通过一系列条件定义从架构/编译器特定的实现中抽象出来asio/detail/fenced_block.hpp其中仅包含单个内存屏障实现。底层实现包含在一个类中,对于该类fenced_block别名是通过 typedef 创建的。

这是相关摘录:

#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
# include "asio/detail/gcc_hppa_fenced_block.hpp"
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
# include "asio/detail/gcc_x86_fenced_block.hpp"
#elif ...

...

namespace asio {
namespace detail {

...

#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
typedef gcc_hppa_fenced_block fenced_block;
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
typedef gcc_x86_fenced_block fenced_block;
#elif ...

...

} // namespace detail
} // namespace asio

内存屏障的实现特定于体系结构和编译器。 Boost.Asio 有一个家族asio/detail/*_fenced_blocked.hpp头文件。例如,win_fenced_block uses InterlockedExchange对于 Borland 来说;否则它使用xchg汇编指令,与内存地址一起使用时具有隐式锁定前缀。为了gcc_x86_fenced_block,Boost.Asio 使用memory组装说明。

如果您发现自己需要使用围栏,请考虑升压原子图书馆。 Boost.Atomic 在 Boost 1.53 中引入,提供了以下实现线程和信号栅栏基于 C++11 标准。在 Boost.Atomic 添加到 Boost 之前,Boost.Asio 一直在使用自己的内存栅栏实现。此外,Boost.Asio 栅栏是基于范围的。fenced_block将在其构造函数中执行获取,并在其析构函数中执行释放。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

asio隐式链和数据同步 的相关文章

随机推荐

  • Android 自定义日历和提醒[关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我的应用程序将包含一个自定义日历 并且根据此日历用户可以创建事件和提醒 问题是 是否可以在 android 中创建自定义日历 我的意思是我想在我的日历中创建事件 这些事件不会出现
  • javascript回调函数,变量映射

    我一直在javascript中使用回调函数 但我从来不明白回调如何知道它可以接受哪些变量 让我们看下面的示例代码 var friends Mike Stacy Andy Rick friends forEach function name
  • 我是否必须修复最新 nuxt.js 的审核问题?

    我正在尝试在我的应用程序中使用 nuxt 但是当我运行 yarn 审计 时 存在一些审计问题 这些问题是 nuxt 的依赖项 我必须解决这些审计问题吗 如果必须的话 我该如何解决它 我正在使用 nuxt 2 15 7 并且添加了最新的css
  • GWT 有哪些效果库可用于商业用途?

    我正在寻找一个可以非常非常轻松地放入我现有的 GWT 应用程序的效果库 我想将库添加到我的构建路径中 然后开始编写类似的内容FX fadeOut thisWidget 取代thisWidget setVisible false GWT 是否
  • Spring Data JDBC 使用 Boot 2.3.0 生成错误的 HSQLDB 查询

    我有一个使用 Spring Data JDBC 的 Spring Boot 项目 测试使用 HSQLDB 当我尝试升级到 Spring Boot 2 3 0 时 我的存储库测试开始失败 Spring Data JDBC 现在似乎引用表名和列
  • 如何在 localhost 中通过 node.js 使用 webodf 编辑器

    我没有找到任何关于如何运行 webodf 的教程 我阅读了他的 api 和源代码 我正在了解如何启动它 任何人都可以分享这个想法 WebODF version 0 5 10 8 gf5949f3 Found Java usr bin jav
  • 在php中,二维数组的行数和列数?

    我有一个元素数量未知的二维数组 two darray row column there will be an unknown integer values instead of row and column keywords 如果我要写一个
  • 创建仅包含整数的列表

    我正在尝试创建一个仅包含另一个列表中的整数的列表 假设我的范围列表是 我希望结果显示为 我希望该解决方案仅适用于 Excel 2019 任何帮助将不胜感激 谢谢 如果您有 Office 365 您可以使用 FILTER A1 A6 INT
  • WTForms 错误:TypeError:formdata 应该是多字典类型包装器

    from wtforms import Form BooleanField TextField validators PasswordField class LoginForm Form username TextField Usernam
  • 短代码呈现为文本而不是短代码应有的形式

    我正在建立一个购物网站 我试图在其中添加一个短代码 该代码将向客户显示购买按钮以及客户想要购买的产品数量 在我的帖子页面上 短代码工作正常 http warringah Plastics com au blog dt catalog rec
  • 计算 iOS 的 CoreMIDI 弯音值?

    我需要手工组装14位MIDI 弯音来自 iOS 中原始 UInt16 值的值 我想知道是否有人有机会提出一个优雅的解决方案 这就是我现在的情况 我可能会在今天晚些时候有机会对此进行测试 但如果我在那之前收到回复 那就太好了 首先 为好奇的人
  • 序列化 CDT 项目设置时遇到了

    当我构建项目时 我收到此错误 Serializing CDT Project settings has encountered a problem Null Pointer Exception 我正在使用最新的 eclipse 并尝试为 A
  • CSS 中的 > 和 ~ 表达式

    CSS 中 和 gt 的用途是什么 例如下面的表达式是什么意思 checked label content gt 您的选择器意味着 选择任意元素这是该类元素的子元素content接下来是label这又遵循 checked输入元素 gt is
  • 如何检查一个列表是否包含另一个列表的所有元素(包括重复项)

    e g t A A A b b s A A b b s 并不包含 t 中的每个元素 t 包含 s 中的每个元素 我想出了这个 但想知道是否有更有效的方法 def check l1 l2 for i in l2 if l2 count i g
  • 实体框架+多级继承+EF代码优先

    我正在尝试使用 Code First 设置 TPC 继承 我有三级继承权 抽象类A 具体类B继承自A 类C继承自B A 类属性 ID CreatedBy 和 CreatedOn B 类属性 FirstName LastName BirthD
  • 图像中的徽标识别[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 有谁知道最近在图像中的徽标识别方面所做的学术工作 请仅在您熟悉该特定主题的情况下回答 我可以自己在 Google 中搜索 徽标识别 非常感谢 任何精
  • RedHat OpenJDK 8 中的 JDK 飞行记录器向后移植

    我想问一下 是否有人知道有关 RedHat OpenJDK 8 生产版本 适用于 RHEL 7 中 JDK 飞行记录器向后移植的日期或更多信息 我已经尝试了最后一个版本 1 8 0 242 b08 但尚未包含它 并且基于这篇文章 https
  • dompdf不显示PHP文件生成的图像

    我正在使用 dompdf 生成 PDF 文件 在该文件中 我包含了一个由 PHP 使用以下命令即时生成的图像 img src image php 当我查看该页面时 我可以看到一条错误消息 未找到图像 该错误链接到据称未找到的图像 当您单击该
  • 如何隐藏浏览器中的状态栏?

    我有一个简单的问题 如何隐藏浏览器状态栏中的链接 我尝试过这个 a href http www sell com referrer 225 Click here a 摘自教程 但这不起作用 如果有人能帮助我 我会很高兴 你不能 至少在当前的
  • asio隐式链和数据同步

    当我阅读asio源代码时 我很好奇asio是如何在线程之间同步数据的 甚至是隐式链的制作 这些是 asio 中的代码 io service 运行 mutex scoped lock lock mutex std size t n 0 for