为什么需要多个shared_future对象来同步数据

2023-12-20

指向数据结构的指针通过以下方式与多个线程共享std::promise and std::shared_future。 从书中'C++ 并发实践' 作者:Anthony Williams(第 85-86 页),似乎只有当每个接收线程使用副本时,数据才会正确同步 的std::shared_future对象而不是每个线程访问单个全局对象std::shared_future.

为了说明这一点,考虑一个线程创建bigdata并将指针传递给具有只读访问权限的多个线程。 如果线程之间的数据同步处理不正确,内存重新排序可能会导致未定义的行为(例如,worker_thread读取不完整的数据)。

这个(不正确?)实现使用单个全局std::shared_future:

#include <future>

struct bigdata { ... };

std::shared_future<bigdata *> global_sf;

void worker_thread()
{
    const bigdata *ptr = global_sf.get();
    ...  // ptr read-only access
}

int main()
{
    std::promise<bigdata *> pr;
    global_sf = pr.get_future().share();

    std::thread t1{worker_thread};
    std::thread t2{worker_thread};

    pr.set_value(new bigdata);
    ...
}

在这个(正确的)实现中,每个worker_thread得到一份副本std::shared_future:

void worker_thread(std::shared_future<bigdata *> sf)
{
    const bigdata *ptr = sf.get();
    ...
}

int main()
{
    std::promise<bigdata *> pr;
    auto sf = pr.get_future().share();

    std::thread t1{worker_thread, sf};
    std::thread t2{worker_thread, sf};

    pr.set_value(new bigdata);
    ....

我想知道为什么第一个版本不正确。

If std::shared_future::get()是一个非常量成员函数,它是有意义的,因为访问单个std::shared_future来自多个线程的数据竞争本身就是一场数据竞争。 但由于这个成员函数被声明为 const,并且global_sf对象与线程同步,从多个线程并发访问是安全的。

我的问题是,为什么只有在每个worker_thread收到一份副本std::shared_future ?


您的实施使用单一的全局shared_future完全没问题,如果有点不寻常的话,这本书似乎是错误的。

[futures.shared_future] ¶2

[ Note:成员函数shared_future不与自身同步,但与共享状态同步。 —end note ]

注释是非规范性的,因此以上内容是多余地明确了规范性措辞中已经隐含的事实。

[种族简介] ¶2

两个表达式求值conflict如果其中一个修改内存位置,而另一个读取或修改同一内存位置。

¶6

某些库调用同步于由另一个线程执行的其他库调用。

[...附加段落定义发生在之前就同​​步而言...]

¶19

两个动作是潜在并发如果它们由不同的线程执行...程序的执行包含一个数据竞赛如果它包含两个潜在并发冲突的操作,至少其中一个不是原子的,并且两者都发生在另一个之前......

[关于数据竞赛的解析] ¶3

C++ 标准库函数不得直接或间接修改当前线程以外的线程可访问的对象,除非这些对象是通过函数的非常量参数直接或间接访问的,包括this.

所以我们知道调用global_sf.get()不同线程中的线程可能是并发的,除非您为它们提供额外的同步(例如互斥体)。但我们也知道这需要global_sf.get()在不同的线程中不会冲突,因为它是一个const方法,因此禁止修改可从多个线程访问的对象,包括*this。因此,不满足数据争用(无序的、可能并发的冲突操作)的定义,程序不包含数据争用。

无论如何,人们通常希望避免全局变量,但这是一个单独的问题。

请注意,如果这本书是正确的,那么它就会包含矛盾。它声称的代码是正确的仍然包含全局shared_future当多个线程创建本地副本时,可以从多个线程访问它:

void worker_thread()
{
    auto local_sf = global_sf; // <-- unsynchronized access of global_sf here

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

为什么需要多个shared_future对象来同步数据 的相关文章

  • 使用空函数调用 hana::is_valid 的用途是什么?

    Boost Hana https www boost org doc libs 1 61 0 libs hana doc html index html offers boost hana is valid https www boost
  • 动态选择和更新 LINQ 结果集中的列值

    我有一个场景 其中存在 LINQ 结果集 我使用了以下查询 var stockDetails from d in db BloodBanks where d bbUserName Session username ToString sele
  • 为什么这个 oracle 批量插入不起作用?

    我正在尝试将一些数据批量插入到 oracle 数据库中 我按照文档中的示例进行操作 this DataBaseAccess new OracleConnection connString var dataAdapter new Oracle
  • 在目标 VS 安装时,VSIX 扩展内部使用的 WPF-Log4Net 未输出日志

    当 Log4net 在 VSIX 扩展中使用并安装在另一个目标 VS 上时 它不会记录日志 我有一个 WPF 解决方案 我下载了 log4net dll 添加了 log4net config 并将 复制到输出目录 值设置为 始终复制 log
  • std::tr1::function 和 std::tr1::bind

    我在使用时遇到问题veryC 类中的复杂 C 函数 重写 C 函数是not一个选项 C函数 typedef void integrand unsigned ndim const double x void fdata unsigned fd
  • 通过用于 Symbol 条码扫描仪 DS4208 的 SNAPI.dll API 捕获图像

    我想通过 SNAPI API 从 Symbol 目前为 Zebra 条形码扫描仪 DS4208 型号 我们还使用 Zebra 的另一个但兼容的型号 捕获图像 条形码捕获 识别效果很好 但看起来像SnapiDLL SNAPI SnapShot
  • 多维数组和指向指针的指针

    创建多维数组时char a 10 10 根据我的书 它说你必须使用类似于char a 10 将数组传递给函数 为什么必须这样指定长度 您不是只是将双指针传递给 with 并且该双指针不是已经指向分配的内存吗 那么为什么参数不能是char a
  • 如何删除实体框架6中的多对多关系

    如果将项目连接为多对多关系 则从数据库中删除项目时会出现问题 我的数据库看起来像 Project lt JobInProject gt Job ProjectID JobInProjectID JobID ProjectID JobID 主
  • 如何在Azure功能中添加razor视图文件?

    我正在创建一个应用程序 它是 azure 函数项目 我想在该项目中使用 Razor 视图 我应该在 azure 函数中使用任何模板引擎吗 得益于一些方面的进步剃刀之光项目 https github com toddams RazorLigh
  • ASP.NET中如何访问除wwwroot以外的位置

    我可以使用访问服务器的物理位置Server MapPath 这给了我内部的物理路径wwwroot文件夹 我想将一些数据保存到同一服务器的另一个驱动器中D 驾驶 我想我无法获取以下位置的物理位置D 驾驶使用Server MapPath因为它位
  • 修改正在运行的可执行文件的资源内容

    All 我将应用程序设置存储在资源中 当我的程序首次加载时 我使用 WinAPI 读取指定的资源 然后我解析检索到的字节数据 这对我来说完美无缺 现在假设用户更改了我的应用程序中的设置 他 她检查复选框控件 我想将更新的设置保存到我的资源中
  • Identity Server 4:添加访问令牌的声明

    我正在使用 Identity Server 4 和隐式流 并且想要向访问令牌添加一些声明 新的声明或属性是 tenantId 和 langId 我已将 langId 添加为我的范围之一 如下所示 然后通过身份服务器请求 但我也获得了tena
  • 为什么这个单独的定义会导致错误?

    挑战 我有这段代码无法编译 你能找出问题所在吗 有一次让我很头疼 header namespace values extern std string address extern int port cpp file std string v
  • 三种 System.Drawing 方法表现出缓慢的绘制或闪烁:解决方案?或其他选择?

    我正在通过 System Drawing 进行一些绘图 但遇到了一些问题 我将数据保存在队列中 并将该数据绘制 绘制 到三个图片框中 此方法填充图片框 然后滚动图形 所以不要在以前的绘图上绘制 并且逐渐看起来更混乱 我找到了两种绘制图表的解
  • 将授权标头添加到 Web 参考

    我正在尝试向客户端的网络服务发出请求 我不知道客户端的底层平台 我使用 添加 Web 引用 在 Visual Studio 2010 中使用了客户端的 WSDL 并生成了我的代理类 称为 ContactService 我现在需要将如下所示的
  • #define 内存地址声明

    这个 define 语句有什么作用 它用于定义内存地址 但我不明白 uint32 t 部分 define GPxDAT uint32 t 0x6FC0 通常用于访问映射到地址空间的硬件寄存器 或者一些特定的内存地址 硬件寄存器应定义为vol
  • 返回 ICollection 而不是 List 的真正优势是什么? [复制]

    这个问题在这里已经有答案了 我读过几篇博客文章 提到对于公共 API 我们应该始终返回 ICollection 或 IEnumerable 而不是 List 返回 ICollection 而不是 List 的真正优势是什么 Thanks 复
  • C# 3.0 中自动属性和公共字段的区别

    我无法理解为什么 C 3 0 中存在自动实现的属性语言功能 当你说的时候有什么区别 public string FirstName than public string FirstName get set 因为它们在生成的 IL 代码 和机
  • asp.net mvc GET 请求上的 formcollection 应该为空

    我正在发布一个简单的操作 public void Login FormCollection formCollection 即使查询字符串值很少 formcollection Count is 0 是靠行为吗 FormCollection 使
  • DataGridView 捕获用户行选择

    我在处理选择时遇到问题DataGridView 我的网格视图包含一个金额列 表单上有一个文本框 应显示所选网格视图行的总数 因此 我需要在用户选择 取消选择 gridview 行时捕获事件并相应地计算 添加 减去 金额 我找到了两种方法 使

随机推荐

  • 将单个文件卷安装为 Docker 中的目录

    Docker 文档 http docs docker com engine userguide dockervolumes mount a host file as a data volume说可以将单个文件挂载到 Docker 容器中 v
  • 玩! 2.0 Scala - 访问全局对象

    我已经声明了一个在应用程序启动时实例化的对象 我想在控制器内访问它 这是插件的一部分 我希望能够使用该插件 但我似乎无法通过第一部分 找到MyWebsocketConnection目的 没有一个示例显示如何执行此操作 我不想注入控制器 因为
  • 如何修复 Prisma Client 自定义模型未定义的问题

    我生成了一个项目打字稿快速启动器 https www npmjs com package typescript express starter并选择了Prisma https www prisma io 作为 ORM 启动项目生成的基本 用
  • python:对我的复制变量的更改会影响原始变量[重复]

    这个问题在这里已经有答案了 我有一个列表 我创建了一个副本 以便在保留原始列表的同时进行一些操作 然而 当我设置copy list等于org list 它们会变成同样的东西 如果我改变copy list org list也发生变化 例如 o
  • Flutter 视频播放器无法在 ios 中播放

    我正在使用 video player 包在 flutter 中播放网络视频 在安卓上运行良好 但在ios上无法加载 颤振3 3 3 视频播放器 2 4 7 PS 服务器调用是https 问题发生在真实设备和响应头有接受范围 字节 Reque
  • 无法在 MySQL 5.7 中添加外键(引用表中缺少约束)

    我正在尝试运行外键添加查询 如下所示 外键检查设置为 0 两个表中的列完全相同 此外 两者都是主键 这里的解决方案都没有帮助解决这个问题 我在本地主机上 mysql gt alter table deliveryaddress gt add
  • 如何从 b 树中删除元素?

    我正在尝试了解 b 树 我能找到的每个来源似乎都忽略了有关如何从树中删除元素同时保留 b 树属性的讨论 有人可以解释该算法或向我指出可以解释其工作原理的资源吗 维基百科页面上有对此的解释 B 树 删除 http en wikipedia o
  • 在发生未处理的异常后,我可以将执行返回到失败的方法吗?

    我有一个 ASP NET 网站 其中包含一些 WCF 服务 我已连接到 Application Error 事件 因此可以记录任何未处理的异常 我真正想做的是将执行传递回被调用的方法 这样我就可以向客户端返回一些有意义的内容 而不是抛出Fa
  • 将按结果分组保存到单独的 CSV 文件中

    我有一个代码 用于使用 CSV 数据创建组并使用该组创建新文件 我读取了 csv 文件 然后使用它 问题是当我的函数工作并使用数据创建新文件时 新文件的名称是组的名称 我不希望这样 ID Inventory Domain Requests
  • Android从缩略图获取图像路径?

    我正在尝试为目前市场上的我的应用程序提供关键更新 我需要查询 MediaStore 中的缩略图 并将缩略图加载到 GridView 中 到目前为止一切顺利 现在我只需要根据我所拥有的内容 即缩略图的路径 获取用户外部存储上实际全尺寸图像的路
  • Oracle复制数据到另一个表

    在Oracle中 我将数据从备份复制到新表 但不起作用 正确的语法是什么 Thanks select CODE MESSAGE into EXCEPTION CODES CODE MESSAGE from Exception code tm
  • 为什么 sizeof(std::mutex)==40 (gcc,clang,icc)? [复制]

    这个问题在这里已经有答案了 而不是sizeof std atomic
  • 使用 SvelteKit 将图像放置在哪里

    我已经使用 Svelte 一段时间了 现在我已切换到 SvelteKit 这样我就可以添加多个页面 我想向我的网站添加一些图像 但我不知道将它们放在哪里 在 Svelte 中我会把它们放进去public images但没有public带有
  • 在 Android 上的 AAC 流中查找

    我从 HTTP 服务器获取 AAC 流并将其用作MediaPlayer在安卓中 它运行得很好 但是当我尝试执行时mediaPlayer seekTo int position 我收到以下错误大约一百万次 WARN AACDecoder 13
  • 处理 PowerShell 脚本中的命令提示符错误

    我正在尝试运行一些命令提示符命令 例如schtasks在 PowerShell 脚本中 我想知道如何处理 PowerShell 中命令引发的错误 I tried cmd exe c schtasks Query TN xx echo ERR
  • System.Messaging - 为什么 MessageQueue 不提供 Send 的异步版本

    有人知道为什么 System Messaging 不提供异步版本的 Send 方法来将 MSMQ 消息发送到队列 实际上有 Peek 和 Receive 方法的异步版本 通过可以转换为 C 5 异步等待方法的 Begin End 对 但令人
  • 初始化一个sqlite数据库android

    大家好 我对 Android 开发还很陌生 我想向我的应用程序添加一个数据库 问题是我不知道如何仅初始化整个表一次 我读了很多书 发现你可以做到 的压倒性作用onCreate SQLiteDatabase db 辅助类中的方法 这些是我的数
  • 全局 Jest SpyOn 函数不调用原始函数

    我希望有人能帮助我理解 js 原型的交互性和jest spOn 我有一个小例子 文件中的示例类TestObj ts export default class TestObj foo Do Something e g console log
  • iOS 7 模拟器日语键盘词典位于哪里?

    这个问题和这个有点相似 如何在 iPhone 模拟器上启用日语键盘 https stackoverflow com questions 8051141 how do i enable the japanese keyboard on the
  • 为什么需要多个shared_future对象来同步数据

    指向数据结构的指针通过以下方式与多个线程共享std promise and std shared future 从书中 C 并发实践 作者 Anthony Williams 第 85 86 页 似乎只有当每个接收线程使用副本时 数据才会正确