- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我在一个线程中写入内存区域(使用 memcpy
),然后在另一个线程中使用 memcpy
将其复制到新位置。有时这些操作可能会重叠,从而导致数据竞争。具有数据竞争的程序会调用未定义的行为并且是无效的。
在这种情况下,我在复制后检查复制的数据是否有效(实际上没有发生竞争。)如果确实发生了竞争,我将丢弃复制的数据。但是,据我所知,这并没有让我摆脱关于 UB 的困境。我认为是否使用数据竞赛的结果仍然是 UB。
现在我可以在汇编中编写自己的 memcpy
例程(或者只是复制并粘贴 libc 中的例程),这将避开整个 UB 问题。汇编不是 C++,汇编中发生的任何事情都不会授予编译器调用鼻恶魔[1] 的许可。顺便说一句,对于内联汇编以及外部编译和链接的汇编来说都是如此吗?虽然 memcpy
已经在任何现代 libc 中汇编,但它也可以由编译器进行特殊处理,编译器通常会像小型内联 memcpy
一样针对已知大小和对齐方式进行优化 - 这可能会再次召唤鼻魔。
我是不是想多了?很难想象一个编译器如此神乎其神以至于它可以在编译时检测到数据竞争——同时又如此愚蠢以至于优化器使用它来生成错误代码而不是报告它。但是编译器最近有办法突破这两个限制 - 所以我觉得有必要在 Stack Overflow 上寻求建议。
[编辑] 由于很多人对我如何在此处同步事物感到好奇,所以让我解释一下。指向正在复制的内存的指针在线程之间共享。它通过原子 load(mo_acquire)
访问。然后将内存复制到新位置。然后是 LoadLoad barrier
,然后是指针的第二个 load(mo_relaxed)
。如果指针不匹配,则复制的结果将被丢弃,因为另一个线程可能在复制期间与该线程竞争。写入内存的线程首先使用原子 store(mo_relaxed)
更新指向 null 的指针,然后是 StoreStore barrier
和 racing memcpy。因此,虽然在不同线程中对 memcpy
的两次调用可能是数据竞争 - 实际上,这种情况总是会被检测到,并且在这种情况下结果总是会被丢弃。我将此方案称为读时复制,并使用它允许在对象被逐出之后但在内存被重新使用之前在缓存中复活对象,而不涉及任何互斥锁或“强”同步。
[1]:我渴望一个更文明的时代,编译器报告 UB 而不是滥用它进行可能与程序员期望的行为相反的优化。
最佳答案
同步锁使用的方法与您正在做的非常相似,尽管只占用非常小的内存。如果数据争用发生率高,同步锁会更快,但如果争用率低,您的方法实际上可能更快。
虽然memcpy的结果是undefined,但这不是undefined behavior,只要你能检测到是否发生了竞争,并且知道是否忽略垃圾结果。
这听起来不像您冒着违反保护或类似崩溃错误的风险;我使用 memcpy 的次数还不够多,无法知道在重叠操作期间是否存在任何可能崩溃的情况,但我认为它不应该。
因此,只要可以检测到行为,这就不一定是坏事,只要它以明显优于标准方法的方式满足您的需求。我不建议“仅仅因为”使用此方法,但是如果您需要使用传统锁无法获得的速度,并且您以通常提供文档的任何方式非常彻底地记录了定义明确但非标准的行为对于维护,这是可以接受的。
至于编译器优化评论,我从未见过编译器依赖未定义的行为来优化代码,并且由于 C++ 编译器需要根据 C++ 规范保证特定行为,我会立即停止使用任何依赖于未定义行为的编译器为此目的的未定义行为。库代码专门记录了不支持且不应执行跨线程同时读/写操作,因此以这种方式跨线程使用库代码不属于未定义行为,而是您自己故意滥用库代码风险,所有明示或暗示的保证均无效。
关于c++ - 与 memcpy 的数据竞争,未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35713190/
初学者 android 问题。好的,我已经成功写入文件。例如。 //获取文件名 String filename = getResources().getString(R.string.filename
我已经将相同的图像保存到/data/data/mypackage/img/中,现在我想显示这个全屏,我曾尝试使用 ACTION_VIEW 来显示 android 标准程序,但它不是从/data/dat
我正在使用Xcode 9,Swift 4。 我正在尝试使用以下代码从URL在ImageView中显示图像: func getImageFromUrl(sourceUrl: String) -> UII
我的 Ubuntu 安装 genymotion 有问题。主要是我无法调试我的数据库,因为通过 eclipse 中的 DBMS 和 shell 中的 adb 我无法查看/data/文件夹的内容。没有显示
我正在尝试用 PHP 发布一些 JSON 数据。但是出了点问题。 这是我的 html -- {% for x in sets %}
我观察到两种方法的结果不同。为什么是这样?我知道 lm 上发生了什么,但无法弄清楚 tslm 上发生了什么。 > library(forecast) > set.seed(2) > tts lm(t
我不确定为什么会这样!我有一个由 spring data elasticsearch 和 spring data jpa 使用的类,但是当我尝试运行我的应用程序时出现错误。 Error creatin
在 this vega 图表,如果我下载并转换 flare-dependencies.json使用以下 jq 到 csv命令, jq -r '(map(keys) | add | unique) as
我正在提交一个项目,我必须在其中创建一个带有表的 mysql 数据库。一切都在我这边进行,所以我只想检查如何将我所有的压缩文件发送给使用不同计算机的人。基本上,我如何为另一台计算机创建我的数据库文件,
我有一个应用程序可以将文本文件写入内部存储。我想仔细看看我的电脑。 我运行了 Toast.makeText 来显示路径,它说:/数据/数据/我的包 但是当我转到 Android Studio 的 An
我喜欢使用 Genymotion 模拟器以如此出色的速度加载 Android。它有非常好的速度,但仍然有一些不稳定的性能。 如何从 Eclipse 中的文件资源管理器访问 Genymotion 模拟器
我需要更改 Silverlight 中文本框的格式。数据通过 MVVM 绑定(bind)。 例如,有一个 int 属性,我将 1 添加到 setter 中的值并调用 OnPropertyChanged
我想向 Youtube Data API 提出请求,但我不需要访问任何用户信息。我只想浏览公共(public)视频并根据搜索词显示视频。 我可以在未经授权的情况下这样做吗? 最佳答案 YouTube
我已经设置了一个 Twilio 应用程序,我想向人们发送更新,但我不想回复单个文本。我只是想让他们在有问题时打电话。我一切正常,但我想在发送文本时显示传入文本,以确保我不会错过任何问题。我正在使用 p
我有一个带有表单的网站(目前它是纯 HTML,但我们正在切换到 JQuery)。流程是这样的: 接受用户的输入 --- 5 个整数 通过 REST 调用网络服务 在服务器端运行一些计算...并生成一个
假设我们有一个名为 configuration.js 的文件,当我们查看内部时,我们会看到: 'use strict'; var profile = { "project": "%Projec
这部分是对 Previous Question 的扩展我的: 我现在可以从我的 CI Controller 成功返回 JSON 数据,它返回: {"results":[{"id":"1","Sourc
有什么有效的方法可以删除 ios 中 CBL 的所有文档存储?我对此有疑问,或者,如果有人知道如何从本质上使该应用程序像刚刚安装一样,那也会非常有帮助。我们正在努力确保我们的注销实际上将应用程序设置为
我有一个 Rails 应用程序,它与其他 Rails 应用程序通信以进行数据插入。我使用 jQuery $.post 方法进行数据插入。对于插入,我的其他 Rails 应用程序显示 200 OK。但在
我正在为服务于发布请求的 API 调用运行单元测试。我正在传递请求正文,并且必须将响应作为帐户数据返回。但我只收到断言错误 注意:数据是从 Azure 中获取的 spec.js const accou
我是一名优秀的程序员,十分优秀!