基本的多线程

时间:2011-11-17 11:41:39

标签: multithreading preemption

我有以下面试问题:

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

有两个并行线程在foo方法中运行。 最后的总和值将在100到200之间变化。 问题是为什么。据我所知,只有一个线程获得一个CPU,并且线程在运行时被抢占。在什么时候干扰会使总和达不到200?

3 个答案:

答案 0 :(得分:10)

增量不是原子的。它读取值,然后写出递增的值。在这两个操作之间,另一个线程可以以复杂的方式与总和进行交互。

值的范围实际上不是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必须依次递增线程B给它的1。

答案 1 :(得分:3)

sum++行是竞争条件。

两个线程都可以读取sum的值为0,然后每个线程将其值递增为1并将该值存回。这意味着sum的值将是1而不是2。

继续这样,你会得到100到200之间的结果。

答案 2 :(得分:0)

现在大多数CPU都有多个内核。因此,如果我们在函数foo()的开头锁定互斥锁并在for循环结束后解锁互斥锁,那么在不同内核上运行的2个线程仍将产生答案200.