主要的原因使用原子能超过互斥,是互斥是昂贵的,但与默认的内存模型atomics是memory_order_seq_cst,这不仅是因为贵吗?
问题:并发使用锁的程序可以和并发无锁程序一样快吗?
如果是这样,除非我想memory_order_acq_rel用于原子,否则它可能不值得.
编辑:我可能会遗漏一些东西,但基于锁定不能比无锁更快,因为每个锁也必须是一个完整的内存屏障.但是,通过无锁,可以使用比内存障碍更少限制的技术.
那么回到我的问题,没有锁定比基于新的C++ 11标准的默认锁定更快memory_model?
"无锁定> =在性能测量时基于锁定"是真的吗?我们假设有2个硬件线程.
编辑2:我的问题不是关于进度保证,也许我正在使用"无锁"脱离上下文.
基本上当你有2个共享内存线程时,你需要的唯一保证就是如果一个线程正在编写然后另一个线程无法读写,我的假设是简单的原子compare_and_swap操作比锁定互斥锁要快得多.
因为如果一个线程甚至从未触及共享内存,您将无缘无故地反复锁定和解锁,但使用原子操作时,每次只使用1个CPU周期.
关于注释,当争用很少时,自旋锁与互斥锁是非常不同的.
Dalvik的内存模型与Java相同吗?我特别感兴趣的是否读取和写入参考和非long/非double原始变量是原子,但我也想知道有没有这两个平台的内存模型之间的差异.
存储是释放操作,负载是两者的获取操作.我知道这memory_order_seq_cst意味着要为所有操作强加一个额外的总排序,但是我没有建立一个例子,如果所有的操作memory_order_seq_cst都被替换,那就不是这样了memory_order_acq_rel.
我是否会遗漏某些内容,或者差异仅仅是文档效果,即memory_order_seq_cst如果有人打算不使用更轻松的模型并且memory_order_acq_rel在约束轻松模型时使用,则应该使用?
假设我们有一个volatile int a.一个线程呢
while (true) {
a = 1;
a = 0;
}
Run Code Online (Sandbox Code Playgroud)
而另一个线程呢
while (true) {
System.out.println(a+a);
}
Run Code Online (Sandbox Code Playgroud)
现在,JIT编译器发出相应的汇编代码是不合法2*a的a+a吗?
一方面,易失性读取的目的是它应该始终从内存中消失.
另一方面,两个读取之间没有同步点,所以我看不出a+a原子处理是非法的,在这种情况下我不会看到如何进行优化2*a会破坏规范.
我们将不胜感激参考JLS.
我经常听说在.NET 2.0内存模型中,写入始终使用释放围栏.这是真的?这是否意味着即使没有明确的内存屏障或锁定,也不可能在不同于创建它的线程上观察部分构造的对象(仅考虑引用类型)?我显然排除了构造函数泄漏this引用的情况.
例如,假设我们有不可变的引用类型:
public class Person
{
public string Name { get; private set; }
public int Age { get; private set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
Run Code Online (Sandbox Code Playgroud)
是否可以使用以下代码观察除"John 20"和"Jack 21"之外的任何输出,例如"null 20"或"Jack 0"?
// We could make this volatile to freshen the read, but I don't want
// to complicate the core of the question.
private Person person;
private void Thread1()
{
while (true)
{
var personCopy = person; …Run Code Online (Sandbox Code Playgroud) 我在StackOverflow的评论中读到了这个:
但是如果你想要安全,你可以在@PostConstruct [方法]的末尾添加简单的synchronized(this){}
[注意变量不易变化]
我认为只有当写入和读取都是在块中执行或者至少读取是易失性时才会强制执行synchronized.
引用的句子是否正确?空synchronized(this) {}块是否将当前方法中更改的所有变量刷新为"一般可见"内存?
请考虑一些场景
如果第二个线程从不调用锁定this怎么办?(假设第二个线程在其他方法中读取).请记住,问题是:刷新对其他线程的更改,而不是给其他线程一种方式(同步)来轮询原始线程所做的更改.在Spring @PostConstruct上下文中,很可能在其他方法中没有同步- 正如原始评论所说.
是仅在另一个线程的第二次和后续调用中强制执行的更改的内存可见性?(请记住,这个同步块是我们方法中的最后一个调用) - 这会将这种同步方式标记为非常糟糕的做法(第一次调用中的陈旧值)
我正在研究VolatileRead/VolatileWrite方法的实现(使用Reflector),我对此感到困惑.
这是VolatileRead的实现:
[MethodImpl(MethodImplOptions.NoInlining)]
public static int VolatileRead(ref int address)
{
int num = address;
MemoryBarrier();
return num;
}
Run Code Online (Sandbox Code Playgroud)
在读取"地址"的值后,如何放置内存屏障?不应该是相反的吗?(在读取值之前放置,所以对于"address"的任何挂起写入都将在我们进行实际读取时完成.同样的事情发生在VolatileWrite,其中内存屏障在赋值之前放置.为什么?另外,为什么这些方法具有NoInlining属性?如果它们被内联会发生什么?
http://en.cppreference.com/w/cpp/atomic/memory_order和其他C++ 11在线参考,将memory_order_acquire和memory_order_release定义为:
这似乎允许在获取操作之前执行获取后写入,这看起来很奇怪(通常的获取/释放操作语义限制所有内存操作的移动).
相同的在线资源(http://en.cppreference.com/w/cpp/atomic/atomic_flag)表明可以使用C++原子和上面提到的宽松内存排序规则构建自旋锁互斥:
lock mutex: while (lock.test_and_set(std::memory_order_acquire))
unlock mutex: lock.clear(std::memory_order_release);
Run Code Online (Sandbox Code Playgroud)
有了这个锁定/解锁的定义,如果确实以这种方式定义了memory_order_acquire/release,那么下面的简单代码就不会被破坏(即,不禁止对获取后写入进行重新排序):
Thread1:
(0) lock
(1) x = 1;
(2) if (x != 1) PANIC
(3) unlock
Thread2:
(4) lock
(5) x = 0;
(6) unlock
Run Code Online (Sandbox Code Playgroud)
以下执行是否可行:(0)锁定,(1)x = 1,(5)x = 0,(2)PANIC?我错过了什么?
我最近在回答一个关于p < q当p和q是指向不同对象/数组的指针时在C 中执行的未定义行为的问题。这让我想到:C ++ <在这种情况下具有相同(未定义)的行为,但是还提供了标准库模板std::less,该模板保证可以返回与<可以比较指针时相同的东西,并在不能比较时返回一些一致的顺序。
C是否提供具有类似功能的东西,从而可以安全地比较任意指针(相同类型)?我尝试浏览C11标准并没有发现任何东西,但是我在C中的经验比在C ++中小得多,因此我很容易错过一些东西。
c pointers memory-model undefined-behavior memory-segmentation