Мне нужно реализовать ту же функциональность, что и эта функция на 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, я переношу шаблон Disruptor от LMAX на C++. Взаимоблокировка происходит, когда один поток находится в SingleThreadedClaimStrategy::WaitForFreeSlotAt()
, а другой в BlockingWaitStrategy::WaitFor
(без тайм-аута). Тупик более очевиден, когда размер RingBuffer крошечный... 1, 2, 4, 8 и т. д.
Потоки создаются обычными CreateThread
средствами.
Редактировать: было довольно поздно, когда я написал это, так что вот еще немного информации. RingBuffer содержит __int64
s. У меня есть один поток Producer и один поток Consumer. Поток Consumer также порождает поток Timer, который каждую секунду опрашивает Consumer на предмет порядкового номера события, которое он использовал в последний раз. Наступает момент, когда Потребитель не продвигается вперед, а Производитель не закончил. Производитель просто запускается в цикле несколько сотен миллионов раз, публикуя счетчик. Итак, мой вывод выглядит примерно так:
898
97
131
Timer: no progress
Timer: no progress
...
Это действительно воспроизводимо только в режиме выпуска, где все оптимизировано для скорости.
::SwitchToThread()
. Он возвращает true или false? - person Managu   schedule 16.08.2012volatile
примитивов, но C++ не делает этого. Читая больше о Disruptor, барьеры памяти выглядят важными. - person Managu   schedule 17.08.2012