Способы найти условия гонки

У меня есть немного кода с условием гонки... Я знаю, что это состояние гонки, потому что это происходит не последовательно, и, похоже, это происходит чаще на двухъядерных машинах.

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

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

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

Это в visual studio 9, с С++ (неуправляемого сорта).

Ответы

Ответ 1

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

Ответ 2

В CLang и gcc 4.8+ есть инструмент, называемый ThreadSanitizer.

Скомпилируйте свой код с помощью флага -fsanitize=thread

Пример:

$ cat simple_race.cc
#include <pthread.h>
#include <stdio.h>

int Global;

void *Thread1(void *x) {
  Global++;
  return NULL;
}

void *Thread2(void *x) {
  Global--;
  return NULL;
}

int main() {
  pthread_t t[2];
  pthread_create(&t[0], NULL, Thread1, NULL);
  pthread_create(&t[1], NULL, Thread2, NULL);
  pthread_join(t[0], NULL);
  pthread_join(t[1], NULL);
}

И вывод

$ clang++ simple_race.cc -fsanitize=thread -fPIE -pie -g
$ ./a.out 
==================
WARNING: ThreadSanitizer: data race (pid=26327)
  Write of size 4 at 0x7f89554701d0 by thread T1:
    #0 Thread1(void*) simple_race.cc:8 (exe+0x000000006e66)

  Previous write of size 4 at 0x7f89554701d0 by thread T2:
    #0 Thread2(void*) simple_race.cc:13 (exe+0x000000006ed6)

  Thread T1 (tid=26328, running) created at:
    #0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
    #1 main simple_race.cc:19 (exe+0x000000006f39)

  Thread T2 (tid=26329, running) created at:
    #0 pthread_create tsan_interceptors.cc:683 (exe+0x00000001108b)
    #1 main simple_race.cc:20 (exe+0x000000006f63)
==================
ThreadSanitizer: reported 1 warnings

Ответ 3

Лучший способ узнать, как это отслеживать, - использовать CHESS в Visual Studio. Это не простой инструмент для использования, и, вероятно, потребуется постепенное тестирование подразделов вашего приложения. Удачи.

Ответ 4

Действительно, есть попытки автоматически найти условия гонки.

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

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

Ответ 8

Вы можете использовать такие инструменты, как Intel Inspector, которые могут проверять определенные типы условий гонки.

Ответ 9

Можно попробовать опубликовать код. Intel также предлагает различные параллельные инструменты, которые вы могли бы попробовать.