В коде C У меня есть 64-разрядное значение в общей памяти, к которому обращаются различные процессы, подключенные к этой общей памяти. В настоящее время чтение и запись покрываются спин-блокировкой, но в компиляторах, где выровненное 64-битное считывание гарантировано не «порвано» (т. Е. Чтение является атомарным), я мог бы опустить покрытие спин-блокинга с «слегка устаревшей» версии значение прекрасное. Код должен быть способен скомпилировать на самых разных аппаратных средствах (включая 32 и 64-разрядные машины: Intel, AMD, Sparc Solaris, IBM Power7 и Power8 и многие другие), операционные среды (включая Linux, Windows и HP-UX) и компиляторы (gcc и clang, многие из которых - C89 или новее); хотя было бы замечательно, если бы я «запустил» на то, чтобы держать шпильки в средах, где безопасность их упускания не могла быть положительно подтверждена. Конечно, более безопасные платформы, на которых я могу определить, что это безопасно, тем лучше.Есть ли #define, чтобы определить, будет ли чтение согласованного 64-битного значения атомарным?
Что является самым безопасным и самым портативным способом определения того, гарантированы ли такие выровненные 64-разрядные чтения из одной 64-разрядной записи?
Основываясь на комментариях до настоящего времени, кажется, лучше показать некоторые из соответствующих кода.
На моей машине, в src/include/pg_config.h
:
/* src/include/pg_config.h. Generated from pg_config.h.in by configure. */
/* src/include/pg_config.h.in. Generated from configure.in by autoheader. */
[...]
/* Define to 1 if `long int' works and is 64 bits. */
#define HAVE_LONG_INT_64 1
Много таких констант времени компиляции определяются на основании того, что обнаруживается, когда ./configure
запускается.
В src/include/c.h
:
/*
* 64-bit integers
*/
#ifdef HAVE_LONG_INT_64
/* Plain "long int" fits, use it */
#ifndef HAVE_INT64
typedef long int int64;
#endif
#ifndef HAVE_UINT64
typedef unsigned long int uint64;
#endif
#elif defined(HAVE_LONG_LONG_INT_64)
/* We have working support for "long long int", use that */
#ifndef HAVE_INT64
typedef long long int int64;
#endif
#ifndef HAVE_UINT64
typedef unsigned long long int uint64;
#endif
#else
/* neither HAVE_LONG_INT_64 nor HAVE_LONG_LONG_INT_64 */
#error must have a working 64-bit integer datatype
#endif
Код я пытаюсь улучшить ниже. oldSnapshotControl
- это указатель на структуру в общей памяти, а threshold_timestamp
- это поле в этой структуре, определяемое как int64
. Обратите внимание на блок XXX
в комментарии к функции.
/*
* Get timestamp through which vacuum may have processed based on last stored
* value for threshold_timestamp.
*
* XXX: If we can trust a read of an int64 value to be atomic, we can skip the
* spinlock here.
*/
int64
GetOldSnapshotThresholdTimestamp(void)
{
int64 threshold_timestamp;
SpinLockAcquire(&oldSnapshotControl->mutex_threshold);
threshold_timestamp = oldSnapshotControl->threshold_timestamp;
SpinLockRelease(&oldSnapshotControl->mutex_threshold);
return threshold_timestamp;
}
Поиск 'stdatomic.h'. Лучше использовать '_Atomic' .. – Olaf
stdatomic.h и _Atomic, похоже, не присутствуют в gcc, так что это не очень портативно. – kgrittn
Очень портативный, так как он является частью стандарта C11. Используйте последнюю версию gcc (начиная с 4.9.something), и вы ее найдете. Если вы используете внешний заголовок, вы получите поддержку для них также в gcc 4.7 и 4.8. Этот файл использует встроенные функции для предоставления '_Atomic' и требуемых определений. IIRC, это BSD-порт (хотя он не зависит от BSD). – Olaf