присутствие взаимного исключения помогает избавлению от энергозависимого ключевого слова?

Вы могли иметь в наличии две зеркальных базы данных? Запишите в одного, сохраните второе как архив. Переключите каждый, скажем, 24 часа (или однако долго Вы считаете соответствующими). В базу данных, которая была архивом, вставьте все сегодняшнее действие. Тогда эти две базы данных должны соответствовать. Используйте это в качестве нового живого дб. Возьмите заархивированную базу данных и сделайте то, что Вы хотите к ней. Можно скопировать/извлечь/читать все, во что Вы хотите теперь, когда то, что я был активно записанным.

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

9
задан Jay D 19 March 2012 в 18:11
поделиться

5 ответов

Здесь есть 2 принципиально не связанных между собой элемента, которые всегда путают.

  • volatile
  • потоки, блокировки, барьеры памяти и т. Д.

volatile используется, чтобы сообщить компилятору для создания кода для чтения переменной из памяти, а не из регистра. И чтобы не переупорядочивать код. В общем, не для оптимизации или «сокращений».

барьеры памяти (обеспечиваемые мьютексами, блокировками и т. Д.), Как процитировано Хербом Саттером в другом ответе, предназначены для предотвращения работы CPU переупорядочивание запросов на чтение / запись в память, независимо от того, как компилятор сказал это сделать. то есть не t optimize, не сокращайтесь - на уровне ЦП.

Подобные, но на самом деле очень разные вещи.

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

Обычные вызовы функций, влияющие на оптимизацию:

external void library_func(); // from some external library

global int x;

int f()
{
   x = 2;
   library_func();
   return x; // x is reloaded because it may have changed
}

, если компилятор не может проверить library_func () и определить, что он не касается x, он перечитает x при возврате. Это даже БЕЗ изменчивости.

Распределение потоков:

int f(SomeObject & obj)
{
   int temp1;
   int temp2;
   int temp3;

   int temp1 = obj.x;

   lock(obj.mutex); // really should use RAII
      temp2 = obj.x;
      temp3 = obj.x;
   unlock(obj.mutex);

   return temp;
}

После чтения obj.x для temp1 компилятор собирается перечитать obj.x для temp2 - НЕ из-за магии блокировок - а потому, что не уверен, lock () измененный объект. Вероятно, вы могли бы установить флаги компилятора для агрессивной оптимизации (без псевдонима и т.д.) и, таким образом, не перечитывать x, но тогда часть вашего кода, вероятно, начнет давать сбой. Если по какой-то причине obj.x может меняться между temp2 и temp3, вы должны использовать volatile (и ваша блокировка будет сломана / бесполезна).

Наконец, если ваши функции lock () / unlock () были каким-то образом встроены, возможно компилятор мог оценить код и увидеть, что obj.x не изменился. Но я гарантирую здесь одно из двух: - встроенный код в конечном итоге вызывает некоторую функцию блокировки уровня ОС (таким образом предотвращая оценку) или - вы вызываете некоторые инструкции барьера памяти asm (т. е. заключенные во встроенные функции, такие как __InterlockedCompareExchange), которые ваш компилятор распознает и, таким образом, избежит переупорядочения.

EDIT: PS Я забыл упомянуть - для pthreads некоторые компиляторы помечены как " POSIX-совместимость ", что означает, среди прочего, что они будут распознавать функции pthread_ и не делать плохих оптимизаций вокруг них. т.е. хотя стандарт C ++ еще не упоминает потоки, эти компиляторы упоминают (по крайней мере, минимально).

Итак, короткий ответ

, вам не нужен volatile.

15
ответ дан 4 December 2019 в 06:19
поделиться

From Herb Sutter's article "Use Critical Sections (Preferably Locks) to Eliminate Races" (http://www.ddj.com/cpp/201804238):

So, for a reordering transformation to be valid, it must respect the program's critical sections by obeying the one key rule of critical sections: Code can't move out of a critical section. (It's always okay for code to move in.) We enforce this golden rule by requiring symmetric one-way fence semantics for the beginning and end of any critical section, illustrated by the arrows in Figure 1:

  • Entering a critical section is an acquire operation, or an implicit acquire fence: Code can never cross the fence upward, that is, move from an original location after the fence to execute before the fence. Code that appears before the fence in source code order, however, can happily cross the fence downward to execute later.
  • Exiting a critical section is a release operation, or an implicit release fence: This is just the inverse requirement that code can't cross the fence downward, only upward. It guarantees that any other thread that sees the final release write will also see all of the writes before it.

So for a compiler to produce correct code for a target platform, when a critical section is entered and exited (and the term critical section is used in it's generic sense, not necessarily in the Win32 sense of something protected by a CRITICAL_SECTION structure - the critical section can be protected by other synchronization objects) the correct acquire and release semantics must be followed. So you should not have to mark the shared variables as volatile as long as they are accessed only within protected critical sections.

13
ответ дан 4 December 2019 в 06:19
поделиться

While this may depend on the threading library you are using, my understanding is that any decent library will not require use of volatile.

In Pthreads, for example, use of a mutex will ensure that your data gets committed to memory correctly.

EDIT: I hereby endorse tony's answer as being better than my own.

4
ответ дан 4 December 2019 в 06:19
поделиться

Вам по-прежнему нужно ключевое слово volatile.

Мьютексы предотвращают одновременный доступ к счетчикам.

«volatile» сообщает компилятору, что он действительно использует счетчик. вместо кеширования в регистр ЦП (что не будет обновляться параллельным потоком).

3
ответ дан 4 December 2019 в 06:19
поделиться

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

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

Итак, вы помечаете переменные как изменчивые, потому что они могут быть изменены извне, а не потому, что они находятся внутри мьютекса.

Сохраняйте их нестабильность.

5
ответ дан 4 December 2019 в 06:19
поделиться
Другие вопросы по тегам:

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