Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Visual Basic .NET или Visual Basic предоставляет возможность впервые использовать потоки в приложениях Visual Basic. Потоки представляют проблемы отладки, такие как условия гонки и взаимоблокировки. В этой статье рассматриваются эти два вопроса.
Исходная версия продукта: Visual Basic, Visual Basic .NET
Исходный номер базы знаний: 317723
Когда возникают условия гонки
Состояние гонки возникает, когда два потока обращаются к общей переменной одновременно. Первый поток считывает переменную, а второй поток считывает то же значение из переменной. Затем первый поток и второй поток выполняют свои операции по значению, и они гонки, чтобы увидеть, какой поток может записать значение последней в общую переменную. Значение потока, записывающего его значение последним, сохраняется, так как поток записывает значение, записанное предыдущим потоком.
Подробные сведения и примеры состояния гонки
Каждый поток выделяется предопределенным периодом времени для выполнения на процессоре. Когда истекает время, выделенное для потока, контекст потока сохраняется до следующего включения процессора, и процессор начинает выполнение следующего потока.
Как может вызвать состояние гонки в одной строке
Изучите следующий пример, чтобы узнать, как происходит состояние гонки. Существует два потока, и оба обновляют общую переменную, называемую total (которая представлена как dword ptr ds:[031B49DCh]
в коде сборки).
Поток 1
Total = Total + val1
Поток 2
Total = Total - val2
Код сборки (с номерами строк) из компиляции предыдущего кода Visual Basic:
Поток 1
1. mov eax,dword ptr ds:[031B49DCh] 2. add eax,edi 3. jno 00000033 4. xor ecx,ecx 5. call 7611097F 6. mov dword ptr ds:[031B49DCh],eax
Поток 2
1. mov eax,dword ptr ds:[031B49DCh] 2. sub eax,edi 3. jno 00000033 4. xor ecx,ecx 5. call 76110BE7 6. mov dword ptr ds:[031B49DCh],eax
Просмотрев код сборки, можно увидеть, сколько операций процессор выполняет на нижнем уровне для выполнения простого вычисления сложения. Поток может выполнять все или часть кода сборки во время процессора. Теперь посмотрите, как происходит состояние гонки из этого кода.
Total
имеет значение 100, val1
равно 50 и val2
составляет 15. Поток 1 получает возможность выполнить, но выполняет только шаги 1–3. Это означает, что поток 1 считывает переменную и завершает добавление. Поток 1 теперь просто ждет, чтобы записать новое значение 150. После остановки потока 1 поток 2 будет полностью выполнен. Это означает, что он записал значение, вычисляемое (85) в переменную Total
. Наконец, поток 1 восстанавливает контроль и завершает выполнение. Он записывает значение (150). Поэтому после завершения потока 1 значение Total
равно 150 вместо 85.
Вы можете увидеть, как это может быть основной проблемой. Если это банковская программа, клиент будет иметь деньги на их счете, которые не должны присутствовать.
Эта ошибка является случайной, так как поток 1 может завершить выполнение до истечения срока действия процессора, а затем Thread 2 может начать выполнение. Если эти события происходят, проблема не возникает. Выполнение потока недетерминировано, поэтому нельзя контролировать время или порядок выполнения. Кроме того, обратите внимание, что потоки могут выполняться по-разному в режиме выполнения и в режиме отладки. Кроме того, можно увидеть, что при выполнении каждого потока в ряде ошибка не возникает. Эта случайность делает эти ошибки гораздо сложнее отслеживать и отлаживать.
Чтобы предотвратить возникновение условий гонки, можно заблокировать общие переменные, чтобы только один поток за раз получил доступ к общей переменной. Сделайте это смешно, так как если переменная заблокирована в потоке 1 и потоке 2 также нуждается в переменной, выполнение потока 2 останавливается, пока поток 2 ожидает, пока поток 1 выпустит переменную. (Дополнительные сведения см SyncLock
. в разделе "Ссылки " этой статьи.)
Симптомы состояния расы
Наиболее распространенным симптомом состояния гонки являются непредсказуемые значения переменных, совместно используемых между несколькими потоками. Это приводит к непредсказуемости порядка выполнения потоков. Когда-то один поток выигрывает, и когда-то другой поток выигрывает. В других случаях выполнение работает правильно. Кроме того, если каждый поток выполняется отдельно, значение переменной работает правильно.
При возникновении взаимоблокировок
Взаимоблокировка возникает, когда две потоки блокируют другую переменную одновременно, а затем пытаются заблокировать переменную, которая уже заблокирована другим потоком. В результате каждый поток перестает выполняться и ожидает освобождения переменной другого потока. Так как каждый поток содержит переменную, которую требует другой поток, ничего не происходит, и потоки остаются взаимоблокируемыми.
Сведения и примеры взаимоблокировок
Следующий код содержит два объекта и LeftVal
RightVal
:
Поток 1
SyncLock LeftVal SyncLock RightVal 'Perform operations on LeftVal and RightVal that require read and write. End SyncLock End SyncLock
Поток 2
SyncLock RightVal SyncLock LeftVal 'Perform operations on RightVal and LeftVal that require read and write. End SyncLock End SyncLock
Взаимоблокировка возникает, когда поток 1 разрешено блокировать LeftVal
. Процессор останавливает выполнение потока 1 и начинает выполнение потока 2. Поток 2 блокируется RightVal
, а затем пытается заблокировать LeftVal
. Так как LeftVal
блокируется, поток 2 останавливается и ожидает LeftVal
освобождения. Так как поток 2 остановлен, поток 1 может продолжать выполняться. Поток 1 пытается заблокировать, но не может, так как поток 2 заблокировал RightVal
его. В результате поток 1 начинает ждать, пока RightVal не станет доступным. Каждый поток ожидает другого потока, так как каждый поток заблокировал переменную, в которую ожидает другой поток, и ни один поток не разблокирует переменную, в которую она хранится.
Взаимоблокировка не всегда возникает. Если поток 1 выполняет обе блокировки перед остановкой процессора, поток 1 может выполнять свои операции, а затем разблокировать общую переменную. После разблокировки переменной Thread 1 поток 2 может продолжить выполнение, как ожидалось.
Эта ошибка кажется очевидной, если эти фрагменты кода помещаются параллельно, но на практике код может отображаться в отдельных модулях или областях кода. Это сложная ошибка для отслеживания, так как из этого же кода может произойти как правильное выполнение, так и неправильное выполнение.
Симптомы взаимоблокировок
Распространенный симптом взаимоблокировки заключается в том, что программа или группа потоков перестает отвечать. Это также называется зависанием. По крайней мере два потока ожидают переменной, заблокированной другим потоком. Потоки не продолжаются, так как ни один поток не будет выпускать свою переменную, пока не получит другую переменную. Вся программа может зависнуть, если программа ожидает выполнения одного или обоих потоков.
Что такое поток
Процессы используются для разделения различных приложений, выполняемых в определенное время на одном компьютере. Операционная система не выполняет процессы, но потоки выполняются. Поток — это единица выполнения. Операционная система выделяет время процессора потоку для выполнения задач потока. Один процесс может содержать несколько потоков выполнения. Каждый поток поддерживает собственные обработчики исключений, приоритеты планирования и набор структур, которые операционная система использует для сохранения контекста потока, если поток не может завершить выполнение в течение того времени, когда он был назначен обработчику. Контекст хранится до следующего времени, когда поток получает время процессора. Контекст содержит все сведения, необходимые потоку для плавного продолжения выполнения. Эти сведения включают набор регистров процессора потока и стек вызовов внутри адресного пространства хост-процесса.
Ссылки
Дополнительные сведения см. в справке Visual Studio для следующих ключевых слов:
SyncLock
. Позволяет заблокировать объект. Если другой поток пытается заблокировать тот же объект, он блокируется до выпуска первого потока. Тщательно используйтеSyncLock
, так как проблемы могут привести к неправильному использованию SyncLock. Например, эта команда может предотвратить условия гонки, но привести к взаимоблокировкам.InterLocked
. Позволяет выбрать набор потоковобезопасных операций в базовых числовых переменных.
Дополнительные сведения см. в разделе "Потоки" и "Потоки".