【发布时间】:2012-08-16 01:45:37
【问题描述】:
我需要在 Win7 x64 上实现与此功能相同的功能。
我最初使用SwitchToThread() 但这不起作用,因为它在极端条件下会导致死锁。我能找到的唯一选择是Sleep(),但这很可能会成为性能杀手,因为它只适用于毫秒分辨率,我仍然不确定它是否与LockSupport.parkNanos() 做同样的事情。
我发现 Java 以纳秒间隔调度(如果发生这种情况)线程的能力很可疑,因此我实现了我只能假设它们会做的事情......旋转。但是我不确定这是否能解决问题,它可能只是延迟不可避免的事情,因为 Java 函数似乎需要 JVM 的干预才能工作。 parkNanos 没有可用的源代码;它在原生 Sun 库中实现。
class LockSupport
{
public:
static void ParkNanos(unsigned __int64 aNanos)
{
ULONGLONG start;
ULONGLONG end;
::QueryUnbiasedInterruptTime(&start);
do
{
// My issue with this is that nothing is actually 'Parked'.
::SwitchToThread();
::QueryUnbiasedInterruptTime(&end);
}
while ((end - start) < aNanos);
}
};
调用代码如下:
void SomeClass::SomeFunction()
{
while (someCond)
{
LockSupport.parkNanos(1L);
}
}
FWIW,我正在将 LMAX 的 Disruptor 模式移植到 C++。当一个线程在SingleThreadedClaimStrategy::WaitForFreeSlotAt() 而另一个线程在BlockingWaitStrategy::WaitFor(没有超时)时,就会发生死锁。当 RingBuffer 的大小很小时,死锁会更加明显...... 1、2、4、8 等。
线程是通过正常的CreateThread 方式创建的。
编辑:我写这篇文章的时候已经很晚了,所以这里有更多信息。
RingBuffer 保存__int64s。我有一个生产者线程和一个消费者线程。 Consumer 线程还生成一个 Timer 线程,该线程每秒轮询 Consumer 以获取它上次消费的事件的序列号。当消费者没有进展并且生产者也没有完成时,就会出现这样的情况。 Producer 只是在循环中运行了几亿次,发布了一个计数器。所以我的输出看起来像这样:
898
97
131
Timer: no progress
Timer: no progress
...
只有在发布模式下才能真正重现,所有内容都针对速度进行了优化。
【问题讨论】:
-
你说你和
::SwitchToThread()陷入僵局。是返回真还是假? -
@Managu 在正常执行期间它可以返回两者。然而,你的评论让我想到了在这个函数返回 false 时旋转这个函数。
-
您如何实现 ReentrantLock 和 Condition,即 BlockingWaitStrategy 使用的?你的锁实现是可重入的吗?条件变量是否原子地获取/释放相应的锁?
-
你有没有在合适的地方插入内存屏障? Java 计算模型明确设置了关于
volatile原语的读写障碍,但 C++ 没有这样做。阅读有关 Disruptor 的更多信息,内存屏障看起来很重要。 -
@Managu 我已将尽可能多的 Java 代码复制到其 Windows 等效代码中。谢谢你的关注。我在这里问过 LMAX 的人:groups.google.com/forum/?fromgroups#!topic/lmax-disruptor/…
标签: java c++ concurrency disruptor-pattern