繁体   English   中英

带线程的 C/C++ 数组 - 我需要使用互斥锁还是锁?

[英]C/C++ arrays with threads - do I need to use mutexes or locks?

我是使用线程的新手,并且已经阅读了很多关于如何共享和保护数据的内容。 但我也没有真正掌握使用互斥锁和锁来保护数据。

下面是我将要解决的问题的描述。 需要注意的重要一点是,这将是时间紧迫的,所以我需要尽可能地减少开销。

我有两个固定大小的双数组。

  • 第一个数组将为后续计算提供数据。 线程将从它读取值,但它永远不会被修改。 某个元素可能会在某个时间被任何线程读取。

  • 第二个数组将用于存储线程执行的计算结果。 这个数组的一个元素只会被一个线程更新,并且可能只有一次当结果值
    是写给它的。

我的问题是:

  1. 每次访问只读数组中的数据时,我真的需要在线程中使用互斥锁吗? 如果是这样,你能解释一下原因吗?

  2. 当线程写入结果数组时,我是否需要在线程中使用互斥锁,即使这将是唯一写入该元素的线程?

  3. 我应该使用原子数据类型吗,如果我这样做会不会有任何显着的时间开销?

  4. 此类问题的许多答案似乎是 - 不,如果您的变量对齐,则不需要互斥锁。 我在这个例子中的数组元素会对齐,还是有什么方法可以确保它们对齐?

该代码将在 64 位 Linux 上实现。 我计划使用 Boost 库进行多线程处理。

几天来我一直在仔细考虑这个问题,并在整个网络上查看,一旦发布,答案和清晰的解释在几秒钟内就回来了。 有一个“接受的答案”,但所有的答案和评论都同样有帮助。

  1. 每次访问只读数组中的数据时,我真的需要在线程中使用互斥锁吗? 如果是,你能解释一下原因吗?

不会。因为数据永远不会被修改,所以不会有同步问题。

  1. 当线程写入结果数组时,我是否需要在线程中使用互斥锁,即使这将是唯一写入该元素的线程?

要看。

  1. 如果任何其他线程要读取该元素,则需要同步。
  2. 如果任何线程可能会修改向量的大小,则需要同步。

在任何情况下,请注意不要由不同的线程大量写入相邻的内存位置。 这可能会破坏性能。 参见“虚假共享”。 考虑到,您可能没有很多内核,因此没有很多线程,并且您说写入仅完成一次,但这可能不会成为一个重大问题。

  1. 我应该使用原子数据类型吗,如果我这样做会不会有任何重要的时间开销?

如果您使用锁(互斥),则不需要原子变量(并且它们确实有开销)。 如果不需要同步,则不需要原子变量。 如果您需要同步,那么在某些情况下可以使用原子变量来避免锁定。 在哪些情况下你可以使用原子而不是锁......我认为这更复杂,超出了这个问题的范围。

鉴于您在评论中的情况描述,似乎根本不需要同步,因此不需要原子或锁。

  1. ...在这个例子中我的数组元素是否会对齐,或者有什么方法可以确保它们对齐?

正如 Arvid 所指出的,您可以使用 c++11 中引入的alginas关键字请求特定对齐。 在 c++11 之前,您可以求助于编译器特定的扩展: https : //gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Variable-Attributes.html

在给定的两个条件下,不需要互斥锁。 请记住,每次使用互斥锁(或任何同步构造)都是一种性能开销。 所以你想尽可能地避免它们(当然不影响正确的代码)。

  1. 不。不需要互斥体,因为线程只读取数组。

  2. 不可以。由于每个线程只写入不同的内存位置,因此不可能出现竞争条件。

  3. 不。这里不需要对对象进行原子访问。 事实上,使用原子对象可能会对性能产生负面影响,因为它会阻止优化的可能性,例如重新排序操作。

只有在共享资源上的数据被修改时才需要使用锁。 例如,如果一些线程用于写入数据而一些用于读取数据(在这两种情况下都来自同一资源),那么您只需要在写入完成时锁定。 这是为了防止所谓的“种族”。

当您制作在共享资源上操作数据的程序时,谷歌上有很好的种族信息。

你走在正确的轨道上。

1)对于第一个数组(只读),您不需要为其使用互斥锁。 由于线程只是读取而不是更改数据,因此线程无法破坏另一个线程的数据

2)我对这个问题有点困惑。 如果您知道线程 1 只会将元素写入数组插槽 1,而线程 2 只会写入数组插槽 2,那么您不需要互斥锁。 但是我不确定你是如何实现这个属性的。 如果我的上述陈述不适合您的情况,您肯定需要一个互斥锁。

3) 鉴于原子的定义:

原子类型是封装一个值的类型,该值的访问保证不会引起数据竞争,并且可用于同步不同线程之间的内存访问。

重点说明,互斥锁是原子的,这意味着只需要 1 条汇编指令即可获取/释放锁。 如果需要 2 个组装指令来抓取/释放锁,那么锁就不是线程安全的。 例如,如果线程 1 尝试获取锁并被切换到线程 2,线程 2 将获取锁。

使用原子数据类型会减少你的开销,但不会显着。

4)我不确定你如何确保你的变量是内衬的。 由于线程可以在您的程序中随时切换(您的操作系统确定线程何时切换)

希望这可以帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM