Моя реализация спин-блокировки корректна и оптимальна?

Это точно не определяется как нуль по сути, это определяется как Календарь. Январь. Это - проблема использования ints как константы вместо перечислений. Календарь. Январь == 0.

37
задан Kim Gräsman 5 September 2009 в 14:41
поделиться

7 ответов

(Примечание: посмотрите на ответ Джо, чтобы узнать, как это сделать это на iOS 8+)

Я просто использую средство форматирования даты:

NSDateFormatter *dateComparisonFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateComparisonFormatter setDateFormat:@"yyyy-MM-dd"];

if( [[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
    …
}

HTH.

* Is it correct?

В упомянутом контексте я бы сказал да.

* Is it optimal?

Это веский вопрос. Изобретая колесо, вы также заново изобретаете множество проблем, которые были решены другими реализациями

  • . Я бы ожидал, что в случае сбоя вы не будете пытаться получить доступ к слову блокировки.

  • Использование полного Барьер в разблокировке должен иметь только семантику выпуска (поэтому вы должны использовать __sync_lock_release, чтобы вы получали st1.rel на itanium вместо mf или lwsync на powerpc, ...). Если вы действительно заботитесь только о x86 или x86_64, типы барьеров, используемых здесь, или не имеют такого большого значения (но если вам, где перейти на Intel Itanium для порта HP-IPF, вам это не понадобится).

  • у вас нет инструкции pause (), которую вы обычно помещаете перед циклом отходов.

  • когда есть раздор, вы хотите чего-то , семопа или даже немого сна в отчаянии. Если вам действительно нужна производительность, которую это дает вам, то предложение фьютекса, вероятно, будет хорошим. Если вам нужна производительность, которую это дает вам достаточно, чтобы поддерживать этот код, вам нужно провести много исследований.

Обратите внимание, что был комментарий, в котором говорилось, что барьер выпуска не требуется. Это неверно даже на x86, потому что барьер выпуска также служит инструкцией для компилятора не перетасовывать другие обращения к памяти вокруг «барьера». Очень похоже на то, что вы получили бы, если бы использовали asm ("" ::: "memory").

* on compare and swap

В x86 sync_lock_test_and_set будет отображаться на инструкцию xchg, которая имеет подразумеваемый префикс блокировки. Определенно самый компактный сгенерированный код (особенно, если вы используете байт для "слова блокировки" вместо int), но не менее правильный, чем если бы вы использовали LOCK CMPXCHG. Использование сравнения и замены может использоваться для более изящных алгоритмов (например, помещение ненулевого указателя на метаданные для первого «официанта» в слове блокировки в случае ошибки).

18
ответ дан 27 November 2019 в 04:53
поделиться

Мне нравится. Кстати, вот реализация учебника , которая более эффективна даже в рассматриваемом случае.

void lock(volatile int *exclusion)
{
    while (__sync_lock_test_and_set(exclusion, 1))
        while (*exclusion)
            ;
}
20
ответ дан 27 November 2019 в 04:53
поделиться

В ответ на ваши вопросы:

  1. Мне кажется, все в порядке
  2. Предполагается, что ОС поддерживает GCC (и в GCC реализованы функции); это должно работать во всех операционных системах x86. Документация GCC предполагает, что будет выдано предупреждение, если они не поддерживаются на данной платформе.
  3. Здесь нет ничего специфичного для x86-64, поэтому я не понимаю, почему бы и нет. Это можно расширить, чтобы охватить любую архитектуру, которую поддерживает GCC, однако, возможно, есть более оптимальные способы достижения этого на архитектурах, отличных от x86.
  4. Возможно, вам немного лучше будет использовать __ sync_lock_release () в случае unlock () ; так как это уменьшит блокировку и добавит барьер памяти за одну операцию. Однако если предположить, что ваше утверждение о том, что разногласия возникают редко; мне это нравится.
4
ответ дан 27 November 2019 в 04:53
поделиться

Я не могу прокомментировать правильность, но заголовок вашего вопроса поднял красный флаг еще до того, как я даже прочитал текст вопроса. Примитивы синхронизации чертовски сложно обеспечить корректность ... если это вообще возможно, вам лучше использовать хорошо спроектированную / поддерживаемую библиотеку, возможно, pthreads или boost :: thread .

2
ответ дан 27 November 2019 в 04:53
поделиться

Одним из улучшений предлагается использовать TATAS (тест-и-тест-и-набор). Использование операций CAS считается довольно дорогостоящим для процессора, поэтому по возможности их лучше избегать. Другое дело, убедитесь, что вы не пострадаете от инверсии приоритета (что, если поток с высоким приоритетом пытается получить блокировку, в то время как поток с низким приоритетом пытается освободить блокировку? В Windows, например, эта проблема в конечном итоге будет решена с помощью планировщик использует повышение приоритета, но вы можете явно отказаться от временного отрезка вашего потока на тот случай, если вам не удалось установить блокировку за последние 20 попыток (например, ..)

0
ответ дан 27 November 2019 в 04:53
поделиться

Ваша процедура разблокировки не требует барьера памяти; присвоение исключения является атомарным, пока оно выровнено по двойному слову на x86.

0
ответ дан 27 November 2019 в 04:53
поделиться

Если вы используете последнюю версию Linux, вы можете использовать фьютекс - «быстрый мьютекс в пользовательском пространстве»:

Правильно запрограммированный Блокировка на основе фьютекса не будет использовать системные вызовы, за исключением случаев, когда блокировка является состязательной

В неоспоримом случае, который вы пытаетесь оптимизировать с помощью спин-блокировки, футекс будет вести себя так же, как спин-блокировка, без необходимости системного вызова ядра. Если блокировка оспаривается, в ядре происходит ожидание без ожидания занятости.

3
ответ дан 27 November 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: