请问mutex_unlock函数作为存储器防护?(Does mutex_unlock functio

2019-08-17 02:18发布

我将描述的情况是发生在iPad 4(ARMv7s),使用POSIX库至互斥锁定/解锁。 我见过的其他ARMv7的设备类似的事情,但(见下文),所以我想任何解决方案都需要在互斥和内存栅栏对ARMv7的行为更普遍的样子。

为方案的伪代码:

线程1 -生产数据:

void ProduceFunction() {
  MutexLock();
  int TempProducerIndex = mSharedProducerIndex; // Take a copy of the int member variable for Producers Index
  mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
  mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable
  MutexUnlock();
}

线程2 -消费数据:

void ConsumingFunction () {
  while (mConsumerIndex != mSharedProducerIndex) {
    doWorkOnData (mSharedArray[mConsumerIndex++]);
  }
}

先前(当问题在iPad 2冒出),I相信mSharedProducerIndex = TempProducerIndex没有被原子方式执行,并且因此改变了使用一个AtomicCompareAndSwap分配mSharedProducerIndex 。 这工作直到这一点,但事实证明我错了,错误已经回来了。 我想“修复”只是改变了一些时间。

我现在已经得出的结论是,实际的问题是一个不折不扣的互斥锁,即在写操作的顺序执行的,如果编译器或者硬件决定重新排序:

mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
mSharedProducerIndex = TempProducerIndex;  // Signal consumer data is ready by assigning new Producer Index to shared variable

... 至:

mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable
mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 

...然后消费者交错生产者,数据也不会尚未当消费者试图读取它写的。

记忆障碍,一些看完后,所以我想我会尝试的信号移到外面消费者mutex_unlock ,相信解锁会产生记忆障碍/栅栏能保证mSharedArray已被写入:

mSharedArray[TempProducerIndex++] = NewData;  // Copy new Data into array at Temp Index 
MutexUnlock();
mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable

然而,这仍然失败,并导致我的问题,如果一个mutex_unlock肯定会作为一个写围栏或不?

我也看到了惠普的一篇文章这表明,编译器可以移动代码到(但不出来的) crit_sec秒。 因此,即使上述变更后的写mSharedProducerIndex可能是障碍了。 是否有任何里程达到这个理论?

通过增加一个明确的围墙问题消失:

mSharedArray[TempProducerIndex++] = NewData; // Copy new Data into array at Temp Index 
OSMemoryBarrier();
mSharedProducerIndex = TempProducerIndex; // Signal consumer data is ready by assigning new Producer Index to shared variable

因此,我想我明白这个问题,那就是需要一个围栏,但任何洞察解锁行为,以及为什么它似乎并没有被执行的障碍将是非常有用的。

编辑:

对缺乏在消费者线程互斥的:我依靠的写int mSharedProducerIndex是一个单一的指令,因此希望消费者会读无论是新的还是旧的价值。 无论是有效状态,并提供mSharedArray写入序列(即写之前mSharedProducerIndex ),这将是好的,但是从已经表示,到目前为止,我不能在此回复。

由相同的逻辑似乎电流阻挡溶液也有缺陷,因为mSharedProducerIndex写入可以在屏障内部移动,并可能因此可能被不正确地重新排序。

它是建议一个互斥体加给消费者,只是作为一个读屏障,或者是有一个pragma对生产者禁止乱序执行,像或指令EIEIO上PPC?

Answer 1:

你会产生被sync'ed但你不这样做(你需要同步与以及记忆障碍)上消耗任何同步。 所以,即使你有生产者内存壁垒不会帮助消费者完美的记忆障碍。

在代码中,你可以通过编译器的排序被击中,硬件订货甚至通过的陈旧值mSharedProducerIndex其他核心正在运行的线程2#。

你应该阅读Chapter 11: Memory Ordering从皮质™-A系列程序员指南 ,尤其是11.2.1 Memory barrier use example

我觉得你的问题是你得到消费者螺纹部分更新。 问题是什么是内生产者关键部分是不是原子,它可以重新排序。

通过not atomic我的意思是,如果你的mSharedArray[TempProducerIndex++] = NewData; 是不是一个字店(NewData为int类型)可能在其中可以通过其他核心的部分更新可以看出以下几个步骤来完成。

通过reordering我的意思是互斥提供壁垒和退出,但关键部分在不强加任何顺序。 因为你没有在消费者身边的任何特殊结构可以看到mSharedProducerIndex被更新,但仍然可以看到部分更新mSharedArray[mConsumerIndex] 互斥只执行离开临界区后,保证内存的知名度。

我相信这也解释了为什么它的工作原理,当你添加OSMemoryBarrier(); 临界区里面,因为这样的CPU被强制将数据写入mSharedArray然后更新mConsumerIndex当其他核心/线程看到mConsumerIndex我们知道mSharedArray复制完全因为阻挡的。

我想您的实现与OSMemoryBarrier(); 是正确的假设你有许多生产者和一个消费者。 我不同意把建议内存屏障消费者任何意见,因为我相信这不会解决部分更新或内部生产关键部分重新排序发生。

作为一个答案,在标题你的问题,一般AFAIK mutex ES已经阅读障碍才能进入,写屏障后,他们离开了。



Answer 2:

“理论”是正确的,写可以​​从一个写栅栏后移动到前。

与您的代码最根本的问题是,有在所有线程2.你读不同步mSharedProducerIndex没有读屏障,所以谁知道珍惜,你会得到。 您在线程1做什么都解决了。



文章来源: Does mutex_unlock function as a memory fence?