Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Поражает воображение, насколько всё это сложно по сравнению с песочницей интерпретируемых языков. Слава суровым дядькам-бородачам!
Spinlock далеко не всегда хуже, чем std::mutex, особенно если важно, чтобы не было слишком больших задержек.Ну я не говорил, что он хуже, но то что он не всегда хуже не значит, что он всегда лучше. Да и более или менее разуменые реализации mutex-ов обычно таки оптимистично ожидают активно некоторое время, т. е. в случае отсутсвия конкуренции, они не должны быть супер плохи.
К тому же, читателям требуется операция проверки — установлена ли эксклюзивная блокировка без её захвата (чтобы не гонять x-state кэш-линии) — такой интерфейс не предоставляют ни std::mutex, ни std::shared_mutex, сюда не подходят ни lock(), ни try_lock().Ну это только часть правды, они действительно такой интерфейс не предоставляют, но без него можно обойтись, как-нибудь так:
void lock_shared() {
int const register_index = register_thread();
if (register_index >= 0) {
int recursion_depth = shared_locks_array[register_index].value.load(std::memory_order_acquire);
assert(recursion_depth >= 1);
if (recursion_depth > 1) {
shared_locks_array[register_index].value.store(recursion_depth + 1, std::memory_order_release);
else {
shared_locks_array[register_index].value.store(recursion_depth + 1);
while (writers.load()) {
shared_locks_array[register_index].value.store(recursion_depth);
for (size_t i = 0; writers.load(); ++i)
if (i % 100000 == 0) std::this_thread::yield();
shared_locks_array[register_index].value.store(recursion_depth + 1);
}
}
}
else {
if (owner_thread_id.load(std::memory_order_acquire) != get_fast_this_thread_id())
mtx.lock_shared();
++recursive_xlock_count;
}
}
void lock() {
int const register_index = get_or_set_index();
if (register_index >= 0)
assert(shared_locks_array[register_index].value.load(std::memory_order_acquire) == 1);
if (owner_thread_id.load(std::memory_order_acquire) != get_fast_this_thread_id()) {
++writers;
mtx.lock();
owner_thread_id.store(get_fast_this_thread_id(), std::memory_order_release);
for (auto &i : shared_locks_array)
while (i.value.load() > 1);
}
++recursive_xlock_count;
}
При 15% изменений, наш shared-mutex (в составе contfree_safe_ptr<map> & rowlock) показывает производительность 8.37 Mops, что в 10 раз быстрее, чем стандартный std::shared_mutex (в составе safe_ptr<map, std::shared_mutex>), который показывает только 0.74 Mops.
The committee has completed work on C++17, which is now in its final ISO balloting process, and aims to begin work on C++20 in July.
Ускоряем std::shared_mutex в 10 раз