Способы найти состояние гонки

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

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

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

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

Это в Visual Studio 9 с С++ (неуправляемого варианта).


person Rokujolady    schedule 28.06.2010    source источник
comment
В прошлый раз, когда у меня было серьезное состояние гонки, я знал, где это происходит. Я сделал это по старинке и прибегнул к построению деревьев вызовов в виде графиков и ручному выделению длительности блокировки для каждого вызова. В моем случае это было ограничено двумя исходными файлами и несколькими функциями, но это оказалось неоценимым.   -  person Nathan Ernst    schedule 29.06.2010


Ответы (8)


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

person Mark Peters    schedule 28.06.2010
comment
Я знаю, что уже довольно поздно комментировать этот ответ, но есть ли какой-нибудь пример, показывающий, как можно использовать «пути сна» для обнаружения условий гонки? - person james; 06.12.2018
comment
@james: Это очень простой подход к анализу условий гонки, и он просто хотел указать, что если у вас есть состояние гонки, которое выигрывает только в 1% случаев, добавление нескольких снов в один из конкурирующих потоков может сделать его победным. ~100% времени, что облегчает диагностику. Поскольку это обязательно требует, чтобы вы много знали о коде (и модифицировали его), здесь трудно привести примеры. - person Mark Peters; 06.12.2018

В 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
person Joakim    schedule 15.01.2016
comment
Thread Sanitizer не обнаруживает условия гонки. Он обнаруживает гонки данных, что не обязательно одно и то же. В вашем примере показано, что стандарт называет гонкой данных, а не состоянием гонки. См. это, чтобы узнать, где не удается обнаружить состояние гонки. - person NathanOliver; 23.03.2018
comment
Однако он не поддерживается в Windows. - person Ignitor; 27.08.2019

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

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

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

person phimuemue    schedule 28.06.2010

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

person Dour High Arch    schedule 28.06.2010

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

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

person jalf    schedule 28.06.2010

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

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

person Rokujolady    schedule 28.06.2010

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

person tojas    schedule 28.06.2010

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

person fons    schedule 14.02.2013