导航

了解多线程临界区

Posted on 2010-04-25 14:52  lilin  阅读(2393)  评论(0编辑  收藏  举报

什么是临界区?

在任意时刻只允许一个线程对共享资源进行访问的区域,也就是多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。 如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。

代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

class Lock
{
    static readonly object lockObj = new object();
    int m = 1;

    public void Run()
    {
        if (m > 0)
        {
            Console.WriteLine(Thread.CurrentThread.Name + "已进入准备睡眠m值:" + m.ToString());
            Thread.Sleep(100);
            Console.WriteLine(Thread.CurrentThread.Name + "减之前m值:" + m.ToString());
            m = m - 1;
            Console.WriteLine(Thread.CurrentThread.Name + "减之后m值" + m.ToString());
            if (m < 0)
            {
                Console.WriteLine("为负数!");
            }
            Console.WriteLine("-----------------");
        }
    }
}

class Test
{
    private static Thread[] trray = new Thread[10];

    public static void Main()
    {
        Lock l = new Lock();

        for (int i = 0; i < 10; i++)
        {
            trray[i] = new Thread(new ThreadStart(l.Run));
        }

        for (int i = 0; i < 10; i++)
        {
            trray[i].Start();
            trray[i].Name = "线程:" + i.ToString(); ;
        }
        Console.ReadLine();
    }
}

运行结果

上面的Run方法按逻辑,辅助线程不可能进入代码块if (m < 0)负数里,但看上图的运行结果,已经进入了.我是为什么呢?
是这样的,首先全局变量m初始值为1,10个线程在运行if (m > 0)时都为True,所以都进入了代码块.Thread.Sleep(100);这名意思是等待10个线程都进入.某一线程执行m=m-1,运行后m值为0.这时注意因m为全局变量,所以这时第二个线程的m值为0,而不是初始值1.减之后就为-1了.

如果想要下图正常的结果,加锁.

public void Run()
    {
        lock (lockObj)
        {
            Console.WriteLine(Thread.CurrentThread.Name + "已进入lock里");
            if (m > 0)
            {
                //代码如上......
            }
        }
    }

 

如果变量m为局部变量,如下代码

public void Run()
    {
        int m =1; 
        if (m > 0)
        {
           //代码如上......
        }
        
    }

不存在多线程临界区,线程是安全的.运行结果如下: