什么是临界区?
在任意时刻只允许一个线程对共享资源进行访问的区域,也就是多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。 如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。
代码:
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) { //代码如上...... } }
不存在多线程临界区,线程是安全的.运行结果如下: