Может LLVM, QEMU, GDB, Bochs, OpenStack или тому подобное, которые будут использоваться для устройстватестировать параллельный код без блокировки на платформе с открытым исходным кодом?Кто-нибудь достиг этого?
Если вы отвечаете рекомендацией программного обеспечения, Я не возражаю, но я упоминаю LLVM, QEMU и другие, потому что они функционируют на разных уровнях.Я хотел бы узнать, на каком уровне был достигнут практический успех при чередовании потоков под контролем юнит-теста.
Мне известно о SPIN / Promela, , между прочим.Это хорошее программное обеспечение, но, насколько я знаю, нельзя скомпилировать C ++, Rust и т. Д. Для цели SPIN / Promela.
Примеры существующих модульных тестов с открытым исходным кодом для параллельного кода без блокировки могут бытьс удовольствием получил, если вы знаете, любой.(Я бы взял источник и изучил бы его, если бы знал, где искать.)
(См. Также эти вопросы и их ответы.)
ПРИМЕР
Мой вопрос, насколько я знаю, не требует примера, так что вы можете проигнорировать этот.Однако, в случае, если пример тестируемого кода без блокировки был полезен для целей обсуждения, вот сравнительно короткий игрушечный пример на C ++.У меня нет модульного теста для него.
#include <atomic>
#include <thread>
#include <cstdlib>
#include <iostream>
const int threshold = 0x100;
const int large_integer = 0x1000;
// Gradually increase the integer to which q points until it reaches the
// threshold. Then, release.
void inflate(std::atomic_bool *const p_atom, int *const q)
{
while (*q < threshold) ++*q;
p_atom->store(true, std::memory_order_release);
}
int main()
{
std::atomic_bool atom{false};
int n{0};
// Dispatch the inflator, letting it begin gradually, in the background, to
// inflate the integer n.
std::thread inflator(inflate, &atom, &n);
// Waste some time....
for (int i = large_integer; i; --i) {}
// Spin until the inflator has released.
{
int no_of_tries = 0;
while (!atom.load(std::memory_order_acquire)) ++no_of_tries;
std::cout << "tried " << no_of_tries << " times" << std::endl;
}
// Verify that the integer n has reached the threshold.
if (n == threshold) {
std::cout << "succeeded" << std::endl;
}
else {
std::cout << "failed" << std::endl;
std::cerr << "error" << std::endl;
std::exit(1);
}
inflator.join();
return 0;
}
Уточнение по Питеру Корду
@ PeterCordes точно проясняет мой вопрос:
Таммогут быть случаи, когда некоторый исходный код компилируется в безопасный x86 asm любым приемлемым компилятором, но небезопасен для слабо упорядоченных ISA, которые также обычно способны выполнять атомарный RMW без полного барьера памяти seq-cst (для переупорядочения во время выполнения; компилировать-время еще до компилятора).Итак, у вас есть два отдельных вопроса: переносим ли исходный код в произвольные системы C ++ 11 и действительно ли ваш код безопасен для x86 (если это все, что вас сейчас волнует).
Оба вопросаМне интересно, но я имел в виду произвольные системы C ++ 11.
Обычно вы хотите написать код, который будет корректно переносимым, потому что он обычно не стоит больше при компиляции для x86.
Ссылка: проект стандарта C ++ 17, n4659 (6 МБ PDF), хорошо объясняет модель параллелизма C ++ 11, на которую ссылается Питер.См. Раздел4.7.1.
ЗАПРОС ДИРКА ХЕРРМАННА
@ DirkHerrmann задает соответствующий вопрос:
Вы спрашиваете о том, как провести модульное тестированиеваш код, но я не уверен, что то, что вы описываете, действительно является сценарием модульного тестирования.Это не означает, что вы не можете использовать ни одну из так называемых структур модульного тестирования (которые на самом деле могут использоваться для всех видов тестов, а не только для модульных тестов).Не могли бы вы объяснить, какова цель ваших тестов, то есть какие свойства кода вы хотите проверить?
Ваша точка зрения хорошо принята.Целью моего теста было бы сбить плохой код надежно для всех возможных моментов времени, поддерживаемых моделью параллелизма C ++ 11.Если я знаю, что код плохой, тогда я смогу написать модульный тест, чтобы провалить его.Моя проблема заключается в следующем:
- Без резьбы. Обычно я могу составить модульный тест для сброса плохого кода, если код без резьбы.
- Резьба. Плохо проваливать, многопоточный код сложнее, но пока мьютексы координируют многопоточность, по крайней мере, код работает аналогично на расходящемся оборудовании.
- Без блокировки. Плохо проваливатьКод без блокировки может быть невозможен на определенном оборудовании.Что, если мой плохой, свободный от блокировок код выходит из строя один раз из миллиарда запущенных на вашем оборудовании, а никогда не сбоит на моем?Как один модуль может протестировать такой код?
Я действительно не знаю, что мне нужно.Поскольку мой процессор x86 не обеспечивает истинную модель параллелизма C ++ 11, возможно, мне нужен эмулятор для несуществующего ЦП, который действительно обеспечивает модель параллельного исполнения C ++ 11.Я не уверен.
Если бы у меня был эмулятор для несуществующего ЦП, который предоставлял истинную модель параллелизма C ++ 11, тогда мой модульный тест (насколько я знаю) должен был бы попробовать мой код при всех возможных, допустимых временных параметрах.
Это не простая проблема.Интересно, решил ли кто-нибудь это.
ОБНОВЛЕНИЕ: CDSCHECKER И RELACY
Дискуссия привела меня к исследованию различных источников, включая
- CDSChecker, программное обеспечение с открытым исходным кодом Норриса и Демского;и
- Relacy Race Detector, программное обеспечение с открытым исходным кодом от Вьюкова, ранее обсуждавшееся здесь .
На данный момент я не делаюзнаю, отвечают ли они на мой вопрос, но выглядят многообещающе.Я связываю их здесь для справки и дальнейшего исследования.
Для полноты справки я также добавляю
уже связано выше.