базовая многопоточность - PullRequest
       21

базовая многопоточность

2 голосов
/ 17 ноября 2011

У меня следующий вопрос Интервью:

class someClass
{
    int sum=0;
    public void foo()
    {
        for(int i=0; i<100; i++)
        {
            sum++
        }
    }
}

В методе foo выполняются два параллельных потока.Значение суммы в конце будет варьироваться от 100 до 200. Вопрос в том, почему.Как я понимаю, только один поток получает процессор, а потоки выгружаются во время работы.В какой момент возмущение может привести к тому, что сумма не достигнет 200?

Ответы [ 3 ]

10 голосов
/ 17 ноября 2011

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

Диапазон значений на самом деле не от 100 до 200. Этот диапазон основан на неверном предположении, что потоки либо сменяются, либо выполняют каждое чтение одновременно. Есть еще много возможных перемежений, некоторые из которых дают заметно разные значения. Наихудший случай выглядит следующим образом (x представляет неявное временное выражение, используемое в выражении sum++):

    Thread A            Thread B
----------------    ----------------
x     ← sum (0)
                    x     ← sum (0)
x + 1 → sum (1)
x     ← sum (1)
x + 1 → sum (2)
⋮
x     ← sum (98)
x + 1 → sum (99)
                    x + 1 → sum (1)
x     ← sum (1)
                    x     ← sum (1)
                    x + 1 → sum (2)
                    ⋮
                    x     ← sum (99)
                    x + 1 → sum (100)
x + 1 → sum (2)

Таким образом, наименьшее возможное значение равно 2. Проще говоря, два потока отменяют тяжелую работу друг друга. Вы не можете опуститься ниже 2, потому что поток B не может подать ноль в поток A - он может только вывести увеличенное значение - и поток A должен, в свою очередь, увеличить значение 1, которое ему дал поток B.

3 голосов
/ 17 ноября 2011

Линия sum++ - это состояние гонки.

Оба потока могут считать значение суммы, скажем, 0, затем каждый увеличивает свое значение до 1 и сохраняет это значение обратно. Это означает, что значение sum будет 1 вместо 2.

Продолжайте в том же духе, и вы получите результат от 100 до 200.

0 голосов
/ 18 ноября 2011

Большинство процессоров теперь имеют несколько ядер.Поэтому, если мы заблокируем мьютекс в начале функции foo () и разблокируем мьютекс после завершения цикла for, тогда 2 потока, работающие на разных ядрах, все равно дадут ответ 200.

...