简体   繁体   English

同步访问变量

[英]Synchronizing access to variable

I need to provide synchronization to some members of a structure. 我需要为结构的某些成员提供同步。
If the structure is something like this 如果结构是这样的

struct SharedStruct {
    int Value1;
    int Value2;
}

and I have a global variable 我有一个全局变量

SharedStruct obj;  

I want that the write from a processor 我想从处理器写

 obj.Value1 = 5; // Processor B

to be immediately visible to the other processors, so that when I test the value 使其他处理器可以立即看到它,以便在测试值时

 if(obj.Value1 == 5) { DoSmth(); } // Processor A
 else DoSmthElse();   

to get the new value, not some old value from the cache. 获取新值,而不是从缓存中获取一些旧值。
First I though that if I use volatile when writing/reading the values, it is enough. 首先,我想如果在写入/读取值时使用volatile ,就足够了。 But I read that volatile can't solve this kind o issues. 但我读到volatile无法解决此类问题。
The members are guaranteed to be properly aligned on 2/4/8 byte boundaries, and writes should be atomic in this case, but I'm not sure how the cache could interfere with this. 保证成员在2/4/8字节边界上正确对齐,在这种情况下,写入应该是原子的,但是我不确定缓存如何干扰这一点。
Using memory barriers (mfence, sfence, etc.) would be enough ? 使用内存屏障(mfence,sfence等)就足够了吗? Or some interlocked operations are required ? 还是需要一些互锁的操作?
Or maybe something like 或者也许像

lock mov addr, REGISTER  

?
The easiest would obviously be some locking mechanism, but speed is critical and can't afford locks :( 最简单的显然是某种锁定机制,但是速度很关键,而且负担不起:(

Edit 编辑
Maybe I should clarify a bit. 也许我应该澄清一下。 The value is set only once (behaves like a flag). 该值仅设置一次(行为类似于标志)。 All the other threads need just to read it. 所有其他线程只需读取即可。 That's why I think that it may be a way to force the read of this new value without using locks. 这就是为什么我认为这可能是一种不使用锁而强制读取此新值的方法。

Thanks in advance! 提前致谢!

There Ain't No Such Thing As A Free Lunch. 没有免费的午餐。 If your data is being accessed from multiple threads, and it is necessary that updates are immediately visible by those other threads, then you have to protect the shared struct by a mutex, or a readers/writers lock, or some similar mechanism. 如果从多个线程访问您的数据,并且其他线程必须立即看到更新,则必须通过互斥锁,读取器/写入器锁或某种类似的机制来保护共享结构。

Performance is a valid concern when synchronizing code, but it is trumped by correctness. 在同步代码时,性能是一个值得关注的问题,但是正确性却使性能大打折扣。 Generally speaking, aim for correctness first and then profile your code. 一般来说,首先要确保正确性,然后再分析代码。 Worrying about performance when you haven't yet nailed down correctness is premature optimization. 在尚未确定正确性时担心性能是过早的优化。

All the other answers here seem to hand wave about the complexities of updating shared variables using mutexes, etc. It is true that you want the update to be atomic. 这里所有其他答案似乎都动摇了使用互斥锁等更新共享变量的复杂性。的确,您希望更新是原子性的。 And you could use various OS primitives to ensure that, and that would be good programming style. 您可以使用各种OS原语来确保这一点,这将是一种很好的编程风格。

However, on most modern processors (certainly the x86), writes of small, aligned scalar values is atomic and immediately visible to other processors due to cache coherency. 但是,在大多数现代处理器(某些情况下 x86)上,小的,对齐的标量值的写入原子的,由于高速缓存一致性,对其他处理器而言,这些写入立即可见。 So in this special case, you don't need all the synchronizing junk; 因此,在这种特殊情况下,您不需要所有同步垃圾。 the hardware does the atomic operation for you. 硬件会为您执行原子操作。 Certainly this is safe with 4 byte values (eg, "int" in 32 bit C compilers). 当然,使用4字节值是安全的(例如,在32位C编译器中为“ int”)。

So you could just initialize Value1 with an uninteresting value (say 0) before you start the parallel threads, and simply write other values there. 因此,您可以在启动并行线程之前使用无趣的值(例如0)初始化Value1,然后在该线程中简单地写入其他值。 If the question is exiting the loop on a fixed value (eg, if value1 == 5) this will be perfectly safe. 如果问题以固定值退出循环(例如,如果value1 == 5),则将是绝对安全的。

If you insist on capturing the first value written, this won't work. 如果您坚持要捕获所写的第一个值,则此操作将无效。 But if you have a parallel set of threads, and any value written other than the uninteresting one will do, this is also fine. 但是,如果您有一组并行的线程,并且除了无趣的线程之外编写的任何值都可以,那么这也很好。

I second peterb's answer to aim for correctness first. 我以彼得的回答为第二,首先以正确性为目标。 Yes, you can use memory barriers here, but they will not do what you want. 是的,您可以在此处使用内存屏障,但是它们不会做您想要的。

You said immediately . 马上说。 However, how immediate this update ever can be, you could (and will) end up with the if() clause being executed, then the flag being set, and than the DoSmthElse() being executed afterwards. 但是,无论此更新有多快,您都可以(并且将要结束if()以执行if()子句,然后设置标志,然后再执行DoSmthElse() This is called a race condition... 这被称为比赛条件...

You want to synchronize something, it seems, but it is not this flag. 您似乎想要同步某些内容,但这不是此标志。

Use explicitly atomic instructions. 使用明确的原子指令。 I believe most compilers offer these as intrinsics. 我相信大多数编译器都将这些作为内在函数提供。 Compare and Exchange is another good one. 比较和交流是另一个很好的选择。

If you intend to write a lockless algorithm, you need to write it so that your changes only take effect when conditions are as expected. 如果打算编写无锁算法,则需要编写无锁算法,以使您的更改仅在条件符合预期时生效。

For example, if you intend to insert a linked list object, use the compare/exchange stuff so that it only inserts if the pointer still points at the same location when you actually do the update. 例如,如果您打算插入一个链接列表对象,请使用比较/交换内容,以便仅在实际执行更新时指针仍然指向相同位置时才插入。

Or if you are going to decrement a reference count and free the memory at count 0, you will want to pre-free it by making it unavailable somehow, check that the count is still 0 and then really free it. 或者,如果您要减少参考计数并在计数0处释放内存,则希望通过某种方式使其不可用来对其进行预释放,请检查该计数是否仍为0,然后真正释放它。 Or something like that. 或类似的东西。

Using a lock, operate, unlock design is generally a lot easier. 使用锁定,操作,解锁设计通常要容易得多。 The lock-free algorithms are really difficult to get right. 无锁算法确实很难正确解决。

Making the field volatile should make the change "immediately" visible in other threads, but there is no guarantee that the instant at which thread A executes the update doesn't occur after thread B tests the value but before thread B executes the body of the if/else statement. 将字段设为volatile应该使更改“立即”在其他线程中可见,但是不能保证在线程B测试该值之后,但在线程B执行主体之前,不会发生线程A执行更新的瞬间。 if / else语句。

It sounds like what you really want to do is make that if/else statement atomic, and that will require either a lock, or an algorithm that is tolerant of this sort of situation. 听起来您真正想做的是使if / else语句成为原子,这将需要一个锁或一个可以容忍这种情况的算法。

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

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