Как я могу проверить алгоритмы без блокировки? - PullRequest
24 голосов
/ 15 января 2010

Теоретически, должна быть возможность, по крайней мере, грубой силы проверить алгоритм без блокировки (существует только так много комбинаций пересекающихся вызовов функций). Существуют ли какие-либо инструменты или формальные процессы рассуждения, чтобы фактически доказать, что алгоритм без блокировки является правильным (в идеале он также должен иметь возможность проверять условия гонки и проблему ABA)?

Примечание. Если вам известен способ доказать только одну точку (например, только доказать, что она безопасна от проблемы ABA) или проблемы, о которой я не упоминал, тогда опубликуйте решение в любом случае. В худшем случае каждый метод может быть выполнен по очереди для полной проверки.

Ответы [ 5 ]

20 голосов
/ 15 января 2010

Вы обязательно должны попробовать Spin модель проверки .

Вы пишете программную модель на простом C-подобном языке, называемом Promela, который Spin внутренне переводит в конечный автомат. Модель может содержать несколько параллельных процессов.

Затем Spin проверяет каждое возможное чередование инструкций из каждого процесса на при любых условиях, которые вы хотите проверить - как правило, отсутствие условий гонки, отсутствие блокировок и т. Д. Большинство из этих тестов могут быть легко написаны с использованием операторов assert(). Если есть какая-либо возможная последовательность выполнения, которая нарушает утверждение, последовательность распечатывается, в противном случае вам дается «полная очистка».

(На самом деле для этого используется гораздо более изящный и быстрый алгоритм, но это эффект. По умолчанию проверяются все достижимые состояния программы.)

Это невероятная программа, получившая премию системного программного обеспечения ACM 2001 *1019* (другие победители - Unix, Postscript, Apache, TeX). Я начал использовать его очень быстро, и через пару дней смог реализовать модели функций MPI MPI_Isend() и MPI_Irecv() в Promela. Спин обнаружил пару сложных условий гонки в одном сегменте параллельного кода, который я преобразовал в Promela для тестирования.

8 голосов
/ 02 февраля 2010

Spin действительно превосходен, но также рассмотрим Relacy Race Detector Дмитрия Вьюкова. Он специально создан для проверки параллельных алгоритмов, включая неблокирующие (без ожидания / без блокировки) алгоритмы. Это с открытым исходным кодом и свободно лицензированы.

Relacy предоставляет примитивы синхронизации POSIX и Windows (мьютексы, условные переменные, семафоры, CriticalSections, события win32, Interlocked * и т. Д.), Поэтому фактическая реализация C ++ может быть передана в Relacy для проверки. Не нужно разрабатывать отдельную модель вашего алгоритма, как с Promela и Spin.

Relacy предоставляет C ++ 0x std::atomic (явное упорядочение памяти для выигрыша!), Поэтому вы можете использовать препроцессор #defines для выбора между реализацией Relacy и вашей собственной атомарной реализацией для конкретной платформы ( tbb :: atomic , boost :: atomic и т. д.).

Планирование является управляемым: доступен случайный, привязанный к контексту и полный поиск (все возможные чередования).

Вот пример программы Relacy. Несколько вещей на заметку:

  • $ - это макрос Relacy, который записывает информацию об исполнении.
  • rl::var<T> помечает «нормальные» (неатомарные) переменные, которые также необходимо учитывать как часть проверки.

код:

#include <relacy/relacy_std.hpp>

// template parameter '2' is number of threads
struct race_test : rl::test_suite<race_test, 2>
{
    std::atomic<int> a;
    rl::var<int> x;

    // executed in single thread before main thread function
    void before()
    {
        a($) = 0;
        x($) = 0;
    }

    // main thread function
    void thread(unsigned thread_index)
    {
        if (0 == thread_index)
        {
            x($) = 1;
            a($).store(1, rl::memory_order_relaxed);
        }
        else
        {
            if (1 == a($).load(rl::memory_order_relaxed))
                x($) = 2;
        }
    }

    // executed in single thread after main thread function
    void after()
    {
    }

    // executed in single thread after every 'visible' action in main threads
    // disallowed to modify any state
    void invariant()
    {
    }
};

int main()
{
    rl::simulate<race_test>();
}

Скомпилируйте с помощью обычного компилятора (Relacy только для заголовков) и запустите исполняемый файл:

struct race_test
DATA RACE
iteration: 8

execution history:
[0] 0:  atomic store, value=0, (prev value=0), order=seq_cst, in race_test::before, test.cpp(14)
[1] 0:  store, value=0, in race_test::before, test.cpp(15)
[2] 0:  store, value=1, in race_test::thread, test.cpp(23)
[3] 0:  atomic store, value=1, (prev value=0), order=relaxed, in race_test::thread, test.cpp(24)
[4] 1:  atomic load, value=1, order=relaxed, in race_test::thread, test.cpp(28)
[5] 1:  store, value=0, in race_test::thread, test.cpp(29)
[6] 1: data race detected, in race_test::thread, test.cpp(29)

thread 0:
[0] 0:  atomic store, value=0, (prev value=0), order=seq_cst, in race_test::before, test.cpp(14)
[1] 0:  store, value=0, in race_test::before, test.cpp(15)
[2] 0:  store, value=1, in race_test::thread, test.cpp(23)
[3] 0:  atomic store, value=1, (prev value=0), order=relaxed, in race_test::thread, test.cpp(24)

thread 1:
[4] 1:  atomic load, value=1, order=relaxed, in race_test::thread, test.cpp(28)
[5] 1:  store, value=0, in race_test::thread, test.cpp(29)
[6] 1: data race detected, in race_test::thread, test.cpp(29)

Последние версии Relacy также предоставляют модели памяти Java и CLI, если вы в такой ситуации.

4 голосов
/ 05 ноября 2013

Если вы хотите действительно проверить код без блокировки (в отличие от исчерпывающего тестирования небольшого экземпляра), вы можете использовать VCC (http://vcc.codeplex.com), дедуктивный верификатор для параллельного кода C, который был использован для проверки некоторых интересных Алгоритмы без блокировок (например, списки без блокировок и изменяемые размеры хеш-таблиц с использованием указателей угроз, оптимистическая обработка транзакций с несколькими версиями, виртуализация MMU, различные примитивы синхронизации и т. д.). Он выполняет модульную проверку и используется для проверки нетривиальных фрагментов промышленного кода примерно до 20KLOC).

Обратите внимание, однако, что VCC является верификатором, а не инструментом поиска ошибок; Вы должны будете сделать существенную аннотацию к своему коду, чтобы заставить его проверить, и кривая изучения может быть немного крутой. Также обратите внимание, что он предполагает последовательную согласованность (как и большинство инструментов).

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

4 голосов
/ 15 января 2010

Обнаружение гонки данных - трудная проблема NP [Netzer & Miller 1990]

Я слышал об инструментах Lockset и DJit + (они обучают этому в курсе CDP). Попробуйте прочитать слайды и поискать, на что они ссылаются. Содержит некоторую интересную информацию.

4 голосов
/ 15 января 2010

Я не знаю, какую платформу или язык вы используете, но на платформе .Net существует проект Microsoft Research под названием Chess , который выглядит очень многообещающим для тех из нас, кто делает многопоточные компоненты - в том числе без блокировки.

Я не использовал это огромное количество, ум.

Это работает (грубое объяснение), явно чередуя потоки самым быстрым из возможных способов, чтобы фактически вытеснить ваши ошибки в дикую природу. Он также анализирует код для выявления распространенных ошибок и неправильных шаблонов - аналогично анализу кода.

В прошлом я также создавал специальные версии рассматриваемого кода (через блоки #if и т. Д.), Которые добавляли дополнительную информацию для отслеживания состояния; количество, версии и т. д., которые я могу затем использовать в модульном тесте.

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

...