Я нашел этот вопрос в учебнике, который я читаю. Решение также приводится ниже. У меня возникли проблемы с пониманием того, насколько минимальным может быть 2. Почему не мог нить читать 0, все остальные потоки выполняются, и он пишет 1? И независимо от того, является ли это 1 или 2, последняя запись потока должна по-прежнему заполнять свой собственный цикл?Несколько потоков, обращающихся к одной переменной
int n = 0;
int main(int argc, char **argv) {
for (i = 0; i < 5; i++) {
int tmp = n;
tmp = tmp + 1;
n = tmp;
}
return 0;
}
Если один поток побежал это приложение, можно было бы ожидать окончательный выхода будет 5. Что делать, если 5 потоков запускали тот же самый цикл в параллели? Какие являются самыми большими и наименьшими значениями, которые могут иметь n? Самый большой должен быть самопомощным: 25, с 5 приращениями из 5 потоков. Тем не менее, рассуждать о наименьшем возможном значении сложнее. Подсказка: n может быть меньше 5, но вам решать, почему.
Решение:
с пятью нитей запуска этих пять-итерация цикла, и без какой-либо защиты от параллельного доступа, самое низкое значение, которое может достигать п равно два. Понимание того, как достичь этого результата, проще всего при работе назад от конечного результата. Для конечного вывода, равного двум, поток должен иметь значение 1 из n, увеличивать его, а затем записывать два. Это означает, что другой поток написал один, подразумевая, что он также изначально читает ноль (который также является стартовым значением для n). Это объясняет поведение двух из пяти потоков. Тем не менее, для выполнения этого поведения, результаты остальных трех потоков должны быть перезаписаны . Для этого можно выполнить два действительных исполнения. Либо 1) все три потока начались и завершили выполнение между первым нулевым нулем и записью первого нуля, или 2) все три потока началось и завершило выполнение между последней прочитанной нитью и , записывающей два. Оба порядка выполнения действительны.
Ну, это просто вызывает неопределенное поведение в потоках C11, поскольку в нем нет забора памяти или атома. –
@MattMcNabb Да. Я должен был включить и первую часть. «Вы видели, что небезопасный доступ из нескольких потоков вызывает непредсказуемые результаты. Но вы также заметили, что некоторые гарантии могут быть извлечены из небезопасных доступов (то есть, если каждый поток пишет 1 , тогда окончательное значение не может быть магическим чем-то другим). Рассмотрим следующий фрагмент кода: « – John
@UserNotDefined: Абсолютно неверно. Если каждый поток пишет 1, и есть условие гонки, вызывающее неопределенное поведение, результатом может быть что угодно. Ваше приложение может просто сбой. – gnasher729