我可以在没有任何锁的情况下从不同的线程读取内存缓冲区吗?

Posted

技术标签:

【中文标题】我可以在没有任何锁的情况下从不同的线程读取内存缓冲区吗?【英文标题】:Can I read a memory buffer from different threads without any lock? 【发布时间】:2018-04-20 21:42:48 【问题描述】:

假设我有一个内存缓冲区,不同的线程想要读取它(所以没有改变它)我需要一个锁来保护它不被并发读取吗?

我知道写,我们应该确保只有一个线程可以写,但是读的情况如何?

为了澄清,缓冲区是一个表,多个线程可以读取并使用它,但它是一个常量表,在程序启动时和任何线程启动之前从磁盘读取。

所以事情就这样发生了:

    程序开始 程序从磁盘读取表值。 程序创建线程并将数据传递给它们。 不同的线程通过读取这个表和其他一些数据来处理数据并生成一些数据,但是没有线程改变这个表。 程序结束。

【问题讨论】:

必须有东西写入该缓冲区,否则它不会包含任何内容。值得一读。 如果内存缓冲区在线程创建之前已被完全写入,则不需要锁/内存屏障。 如果你知道有(而且永远不会有)任何作家——那就是;数据是静态的。那么不,你不需要任何锁。但是如果数据可能会改变,那么你确实需要锁。 【参考方案1】:

假设我有一个内存缓冲区,不同的线程想要读取它(所以没有改变它)我需要一个锁来保护它不被并发读取吗?

只要您在填充缓冲区后执行此读取操作,则不需要任何同步。只要您只从同一个对象中读取,就不需要同步。

只有当您有一个或多个写入者尝试修改对象,或者您有一个或多个写入者尝试修改对象而一个或多个读取者尝试读取其值时,您才需要同步。

【讨论】:

如果没有缓存一致性,写入可能不会被多核处理器中的其他核心看到。【参考方案2】:

如果多个线程正在读取缓冲区,而没有一个线程正在写入,那么并发读取通常不是问题。例如,如果在创建线程之前填充缓冲区并且从未更改过,则读取可以是并发的而无需锁定。

如果任何线程正在修改缓冲区,则读取和写入都需要锁定。这对于防止写入干扰读取和写入是必要的 - 例如,防止在部分写入时读取缓冲区的情况。

【讨论】:

【参考方案3】:

我需要一个锁来保护它不被并发读取吗?

没有。

但是,如果有比您的线程更早进行的写入,那么,根据您所在的机器 - 稍后的读取可能会返回不同的值。

【讨论】:

这怎么可能? @LWimsey:非缓存一致性架构。请参阅***上的this - 这是相当多的开销。在某些多核处理器(更不用说多插槽)上,某些缓存级别无法保持一致;因此,最近在一个内核上的写入可能不会一直传播回实际 RAM,然后会使其他内核上的低级缓存失效,然后从该地址读取。 有趣的观点,但它违反了 C++ 标准要求,即在线程创建之前排序的内存操作在线程本身内部可见(N4713,第 33.3.2.2-6 [线程构造函数])在平台上如果没有缓存一致性,可能会出现不连贯的内存视图(加载返回陈旧值),但不会在同步之后。 @LWimsey:我实际上是在考虑写入期间线程何时已经存在。

以上是关于我可以在没有任何锁的情况下从不同的线程读取内存缓冲区吗?的主要内容,如果未能解决你的问题,请参考以下文章

python多线程读取只读内存缓冲区绕过GIL

如何在没有任何循环php的情况下从数组中随机获取项目

在以下情况下从套接字读取数据已损坏?

为啥我可以在没有任何配置文件的情况下从 App Store 运行应用程序?

在不使用 UTL_FILE 的情况下从 PL/SQL 中的文件读取/写入数据

如何在不选择任何行的情况下从 iphone 的表格视图单元格中读取值