Как доказать, что многопоточность работает? - PullRequest
3 голосов
/ 05 октября 2009

Как я могу доказать, что многопоточность работает в моих программах на C #? Это для тестирования. Например, мне нужно добавить некоторые блокировки в класс логгера (да, я знаю, я не должен был писать свой собственный класс логирования), и мне нужен тестовый пример, чтобы доказать, что изменение будет работать.

Ответы [ 8 ]

7 голосов
/ 05 октября 2009

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

Это широкая тема, и вы можете найти несколько связанных вопросов по StackOverflow, которые стоит прочитать:

CHESS - это разрабатываемая структура для выявления «нарушений утверждений, взаимоблокировок, блокировок в реальном времени, гонок данных и ошибок модели памяти». Я на самом деле не использовал это, но похоже, что это может быть очень полезно.

5 голосов
/ 05 октября 2009

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

Многопоточный код - проклятие моего существования во многих проектах. Часто люди / разработчики не имеют опыта, необходимого для хорошей работы. Ошибки часто остаются незамеченными в течение длительных периодов времени, прежде чем кто-либо увидит их в дикой природе, и тогда вы не сможете воспроизвести проблему, чтобы определить, что происходит. Кроме того, попытка «исправить» неисправный многопоточный код с помощью отладки часто не является жизнеспособным подходом.

Во всяком случае, продолжайте и проверьте это, нет ничего плохого в том, чтобы делать так много, и это достаточно легко сделать. Просто запустите N потоков, пусть они все ждут на ManualRestEvent, а затем вызовите свой API в тесной петле пару сотен тысяч раз :). Но сначала я бы порекомендовал всем членам вашей команды выполнить проверку кода. Пройдите каждую строку кода, думая о его параллельном выполнении. Задайте себе вопрос:

  1. Мне действительно нужен этот замок ()?
  2. Какой наименьший объем кода ДОЛЖЕН быть в блокировке ()?
  3. Могу ли я сделать этот объект / состояние неизменным и избежать блокировки?
  4. Есть ли способ для вызывающей стороны, чтобы код выполнялся внутри блокировки?
  5. Просмотр всех членов, к которым обращались и которые меняли внутри замка на «volatile»?
  6. Правильно ли вы используете System.Threading.Thread.MemoryBarrier?
  7. Если задействованы несколько блокировок, всегда ли они получаются в одном и том же порядке?
  8. [вики добавить сюда]
1 голос
/ 28 марта 2011

+ 1 другому парню, который предложил использовать Thread.Sleep ()

Я обнаружил, что Thread.Sleep () очень полезен для симуляции различных условий гонки. Однако по понятным причинам вам необходимо убедиться, что вы удалили (или использовали конфигурацию для отключения) Thread.Sleep перед развертыванием в рабочей среде.

В книге Роберта С. Мартина «Чистый код» он рекомендует использовать «стратегии покачивания» в своих модульных тестах для выявления проблем с многопоточностью. Jiggling включает в себя добавление случайного времени ожидания в ваш код, чтобы потоки работали в разном порядке в разное время. Затем вы можете запускать свои юнит-тесты много раз, и ваше покачивание может устранить некоторые недостатки. Важно НЕ игнорировать любые сбои модульного теста, связанные с многопоточностью, только потому, что они пройдут при следующем запуске теста.

Рэнт: Я не уверен, почему кто-то проголосовал против другого ответа, который предлагает использовать Thread.Sleep, по крайней мере, не комментируя, почему он проголосовал за него.

1 голос
/ 05 октября 2009

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

0 голосов
/ 10 октября 2009

Другая тема опубликовала связанный ответ, используя программу Microsoft CHESS .

0 голосов
/ 05 октября 2009

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

WriteA();
// potential race condition as another bit of code might read all the state
// and only get A in their read.
WriteB();

до

WriteA();
Thread.Sleep(60000);
WriteB();

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

0 голосов
/ 05 октября 2009

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

0 голосов
/ 05 октября 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...