我需要用锁来保护这个变量吗?

发布于 2024-09-08 16:52:19 字数 900 浏览 5 评论 0原文

所以我在多处理器机器上有一个 C++ 布尔类型。该变量一开始是 true,然后有几个线程,其中任何一个或多个都可能将其写入 false。

同时,这些线程也可能读取这个变量来检查它的状态。我不关心读取此变量是否与任何写入同步,它们各自发生在代码中的不同位置,并且它是否发生在任何特定写入之前或之后并不重要。现在,我需要为这个布尔值加锁吗?

我需要锁的唯一方法是,如果在非常低的级别,内存可能会被两个竞争写入损坏。例如,如果处理器 A 上的汇编指令正在将 0 写入表示布尔值的字节,同时处理器 B 也执行相同操作...并且内存最终不是写入 0,而是值为 22 或某物。这可能会把事情搞砸。

因此,一般来说,如果 proc A 将 3 写入内存位置,而 proc B 正在写入 7,并且没有同步,我是否能保证最终至少得到 3 或 7?还是记忆就那么容易被破坏?

编辑:

谢谢大家的评论。更多信息:当然,程序中有同步。总而言之,所讨论的标志表明某个内存池是否“脏”(需要压缩)。因此,任何线程都可以决定将此标志设置为 false(意味着池是脏的)。例如,从池中释放内存会使其变脏。然后,任何线程也可以读取此标志并设置另一个标志来表示需要进行清理——此检查是在从池中分配内存时完成的,如果内存不足,则会发出清理信号。在迭代之间的主关键部分的某个位置,每个线程都会寻找更多要处理的数据,我将让线程检查第二个标志,并执行适当的操作以确保:所有其他线程完成当前迭代,一个线程清理内存,将第一个标志设置回 true(如池不脏),将第二个标志设置回 false,然后再次释放所有线程。

所以我认为我不需要锁,因为:锁将确保写入不会与另一个写入或读取同时发生。但谁在乎呢,只要硬件不会让我失望,最坏的情况是读取在写入之前或之后随机发生——这与我用锁保护它时会发生的情况是一样的,就在那时我们真的确定它是在之前还是之后......

我认为同样的论点也适用于我上面提到的第二个标志。

so I have a boolean type in C++ on a multiprocessor machine. The variable starts out life as true, and then there are a few threads, any one or more of which might write it to be false.

At the same time, these threads may also read this variable to check its state. I don't care if reading this variable is synchronized with any of the writes, they each happen at different places in the code, and it doesn't matter if it comes before or after any particular write. Now, do I need a lock for this boolean?

The only way I would need a lock is if at the very low level, memory can get corrupted by two competing writes. If, for example, an assembly instruction on processor A is writing 0 to the byte that represents the boolean at the same time as processor B is doing the same... and instead of having written 0, the memory ends up with value 22 or something. That could mess something up.

So, generally, if proc A is writing 3 to a memory location, while proc B is writing 7, with no synchronization, am I guaranteed to end up with at least either 3 or 7? Or is it that easy to break memory?

Edit:

Thanks for the comments guys. Some more info: There is synchronization in the program of course. To summarize, the flag in question is telling if a certain memory pool is "dirty" (needs to be compacted). Any thread can hence decide to set this flag to false (meaning pool is dirty). For example, freeing memory from the pool makes it dirty. Any thread can then also read this flag and set another flag to signal that a clean-up is needed -- this check is done when memory is allocated from the pool, the clean-up is signaled if we're low on memory. Somewhere in my master critical section between iterations, where each thread goes to look for more data to process, I will have the threads check this second flag, and do something appropriate to make sure that: all other theads finish their current iteration, one thread cleans up the memory, sets the first flag back to true (as in pool is not dirty), sets the second flag back to false, and then releases all the threads again.

So I don't think I need a lock because: a lock would ensure that a write doesn't happen at the same time as another write or a read. But who cares, as long as the hardware doesn't fail me, the worst-case-scenario is that the read happens randomly before or after the write -- this is the same thing that would happen if I protected it with a lock, just then we'd really be sure it came before or after...

I think the same argument applies to the second flag I mentioned above.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你穿错了嫁妆 2024-09-15 16:52:19

在大多数商用硬件上,单个字读/写是原子的,因此不会,对同一内存位置的两个(或更多)竞争写入(和读取)不会破坏该值。这里重要的是 CPU 之间的缓存一致性

同样,在商用硬件上,您可能只需标记单个布尔变量易失性(顺便说一句,它已被声明对并发编程无用)以防止编译器将其优化到寄存器中,但是仅当您确实不关心写入顺序时才如此。

让我用一个清单来重申这一点:

  • 您准备好丢失该布尔值的一些更新了吗?
  • 您确定源代码中布尔翻转之前没有其他内存更新但可能会在该翻转之后重新排序,这会让事情变得混乱吗?
  • 您确定不关心应用程序中事件的顺序吗?

如果您有三个强烈的“是”答案,您可能可以不保护该标志。仍然考虑在读取变量之前插入获取内存屏障,并在写入变量之前插入释放内存屏障。不过,我的建议是重新考虑设计,并制定清晰的同步线程间通信和事件排序。

希望这有帮助。

On most commodity hardware a single word reads/writes are atomic, so no, two (or more) competing writes (and reads) to the same memory location are not going to corrupt the value. What is important here is cache coherence between CPUs.

Again, on commodity hardware you might get away with just marking that single boolean variable volatile (which has been declared useless for concurrent programming btw) to prevent compiler from optimizing it out into a register, but only if you really don't care about the order of writes.

Let me re-iterate this with a check-list:

  • Are you ready do lose some updates to that boolean?
  • Are you sure no other memory updates that come before the boolean flip in the source code but might get reordered after that flip are going to mess things up?
  • Are you sure you don't care about order of events in your application?

If you have three strong "yes" answers, you might get away with not protecting that flag. Still consider inserting acquire memory barrier before reading the variable, and release memory barrier before writing it. My suggestion though would be to re-think the design, and lay out clear synchronous inter-thread communications and event sequencing.

Hope this helps.

仙气飘飘 2024-09-15 16:52:19

如果您只是检查变量的状态并将其在一个方向上设置为 false,则无需担心太多,只是某些线程可能会有点晚才看到变量已设置为 false。 (这可以在某种程度上通过使用“易失性”关键字来克服。)然后两个线程可以将其设置为 false,这没有问题,因为变量在一个方向上设置为单个值。假设对内存位置的布尔写入不能保证是原子的,有什么危害?他们两者写入的最终值是相同的。

尽管如此,如果出现以下情况,您将必须使用一种锁定方法:

  • 值设置不仅仅是单向的:您将其设置为 false,然后返回 true,然后再次设置为 false,等等。
  • 您对线程所拥有的信息采取一些相关操作将值设置为 false。因为显然可能有两个赢家。

If only you're checking the state of the variable and setting it to false in one direction ever, there's not much to worry about except that some of the threads may be a little late to see the variable is already set to false. (this may be overcome to some degree by the use of 'volatile' keyword.) Then two threads may set it to false, which is no problem since the variable is set to a single value in one direction. Let's say boolean write to the memory location is not guaranteed to be atomic, what's the harm? The final value they both will write is the same.

Still, you would have to use a method of locking if:

  • Value setting is not one-direction only: you set it to false, then back to true, then false again, etc.
  • You take some dependent action on the information which thread had set the value to false. Because there obviously may be two winners.
霞映澄塘 2024-09-15 16:52:19

这是破坏事物的简单方法。使用布尔值,大多数时候可能没问题,但没有提供任何保证。

您有两个选择:使用互斥体(锁),或使用原子原语。原子原语将利用硬件指令以线程安全的方式进行测试和设置操作,而不需要实际的互斥体,并且是一种轻量级的解决方案。 GNU 编译器通过特定于体系结构的扩展提供对原子操作的访问。还有一些可移植的原子操作库; Glib C 库提供原子操作,如果原子原语不可用,则回退到使用互斥体,尽管它是一个相当重的库,还有许多其他功能。

Boost.Atomic 库,它抽象了 C++ 的原子操作;从它的名字来看,它的目标是被纳入 Boost C++ 库集合中,但并没有但还是做到了。

It's an easy way to break things. With a boolean, you may be ok most of the time, but are provided no guarantees.

You have two options: use a mutex (lock), or use atomic primitives. Atomic primitives will utilize hardware instructions to do the test and set operations in a thread-safe fashion without requiring an actual mutex and are a lighter-weight solution. The GNU compiler provides access to atomic operations via architecture-specific extensions. There are also portable atomic operation libraries floating around; the Glib C library provides atomic operations that fall back to using a mutex if atomic primitives are not available, although it is a fairly heavy library with many other features as well.

There is the Boost.Atomic library which abstracts atomic operations for C++; based on its name, it looks like it is aiming to be incorporated into the Boost C++ library collection but hasn't yet made it.

思念绕指尖 2024-09-15 16:52:19

你问的是两件事。

首先,您询问 bool 赋值的原子性。不,不能保证布尔赋值将是原子操作。实际上通常是这样,但您不应该依赖于此。一些奇怪的架构可能会在许多机器指令中实现布尔赋值...

其次,您会询问由于并行写入而导致的数据损坏 - 实际上,从 CPU 到内存的传输是通过总线完成的,总线几乎总是包含比您的原始类型更多的位正在努力。因此,对于非常奇怪的架构或处理大数字(系统本身不支持)时,可能会发生这种损坏。实际上,您通常会得到 3 或 7 个。但同样,您不能依赖它。

总而言之——你需要一把锁。

You are asking about two things.

First you are asking about atomicity of bool assignment. No there is no guarantee that boolean assignment will be atomic operation. In practice it usually is, but you shouldn't rely on this. Some strange architecture may implement bool assignment in many machine instructions...

Secondary you are asking about corruption of data due to parallel writes - in practice transport from CPU to memory is done by a bus, which almost always contains more bits than primitive types you are working on. So such corruption may happen for very strange architecture or when working on big numbers (not supported by the system natively). In practice you will usually get 3 or 7. But again, you can't rely on it.

To conclude this - you need a lock.

×眷恋的温暖 2024-09-15 16:52:19

在大多数商用硬件上,单字读取和写入不是原子操作;请记住,这里有虚拟内存机器,这些操作中的任何一个都可能导致页面错误。

更一般地说,您可能会发现将互斥体作为一种常规使用比挠头想知道这次是否会摆脱互斥体更容易、更快捷。在不需要的地方添加一个不会导致错误;留下一个可能的地方。

On most commodity hardware single word read and writes are not atomic operations; remember you have virtual memory machines here and either of those operations might cause a page fault.

In more general terms you'll probably find it easier and quicker to use mutexes as a matter of routine than scratch your head wondering if you are going to get away without one this time. Adding one where it isn't necessary doesn't cause a bug; leaving one out where it is might.

ゝ偶尔ゞ 2024-09-15 16:52:19

对于布尔值,答案通常是否定的,不需要互斥体,但是(正如 Michael E 指出的)任何事情都可能发生,因此在做出这样的决定之前,您可能需要更多地了解您的架构。另一个注意事项:代码可能仍然需要锁定与 bool 相关的整体逻辑,特别是如果在例程逻辑过程中多次读取 bool 的话。

我读了一些很棒的博客,让我保持多线程的警惕:

链接

http://herbsutter.com/2009/04/20/ effective-concurrency-use-thread-pools- Correctly-keep-tasks-short-and-nonblocking/

最好的问候,

For a bool, the answer is generally no, a mutex is not needed, but (as Michael E noted) anything could happen, so you likely need to understand more about your arch before making such a decision. Another note: the code might still need a lock around the overall logic associated with the bool, especially if the bool is read more than once in the course of a routine's logic.

Some great blogs I read to keep me on my multithreaded toes:

Link

http://herbsutter.com/2009/04/20/effective-concurrency-use-thread-pools-correctly-keep-tasks-short-and-nonblocking/

best regards,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文