日期:2014-05-17  浏览次数:20727 次

关于线程同步的问题,求解
有个小程序如下:

public class shareMemory
{
    public int Memory { get; set; }
}
public class increaseMemory
{
    private shareMemory test;
    public increaseMemory(shareMemory obj)
    {
        this.test = obj;
    }
    public void increase()
    {
        for (int i = 0; i < 100000; i++)
        {
            test.Memory++;
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        shareMemory obj = new shareMemory();
        Task[] tasks = new Task[5];
        for (int i = 0; i < 5; i++)
        {
            tasks[i] = new Task(new increaseMemory(obj).increase);
            tasks[i].Start();
        }
        for (int i = 0; i < 5; i++)
        {
            tasks[i].Wait();
        }
        Console.WriteLine(obj.Memory);
        Console.ReadKey();
    }
}

问题是如果我不将共享对象设置为线程安全对象,那么程序计算结果就不会是正确结果,但是这五个线程即便会出现打断彼此的情况,也应该会记录自己的运行情况。在获得CPU的使用权的时候也还是能够按照原来的断点继续运行。也就是说即便打断也能够自加100000次。求解答,各位大神
线程

------解决方案--------------------
这是最基本的常识问题
test.Memory++;
不是原子操作。
它相当于这样一些操作:
int x = test.Memory; line 1
x = x + 1;           line 2
test.Memory = x;     line 3
我们假设Memory目前等于1。
A线程开始执行前两条,执行到2,此时x=2
A线程被打断,B线程开始执行前两条,B线程的局部变量(不是前面的那个x)x=2
此时B线程挂起,执行A线程第三行,test.Memory=2
B线程此时的x是脏数据,还是2,它用这个数据去更新,结果test.Memory还是2。

可见我们做了2个相加的操作,结果其实只加了一次。
更糟糕的是,如果A线程做了10次,B线程切入,那么它还是用2去覆盖,等于A线程的9次相加全白费了。