当多个线程同时对一个资源进行操作的时候,便会引发问题,这个时候就需要线程同步,比较典型的就是多线程执行加减操作。
解决方式:
先介绍一下线程不同步的情况
private static List nums;
private static int count;
static void Main(string[] args)
{
nums = new List();
for (int i = 0; i < 20; i++)
{
nums.Add(i);
}
Thread t1 = new Thread(TestFun);
t1.Name = "thread_1";
Thread t2 = new Thread(TestFun);
t2.Name = "thread_2";
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadKey();
}
private static void TestFun()
{
while (nums.Count > 0)
{
Console.WriteLine("----------"+Thread.CurrentThread.Name + " num:" + nums[0]+"-------------");
Console.WriteLine(Thread.CurrentThread.Name + " num:" + nums[0]+" Enter");
if (nums.Count > 0)
{
Console.WriteLine(Thread.CurrentThread.Name + " num:" + nums[0] + " StartRemove");
nums.RemoveAt(0);
}
if (nums.Count > 0)
{
Console.WriteLine(Thread.CurrentThread.Name + " num:" + nums[0] + " EndRemove");
Thread.Sleep(1);
}
}
}
执行结果
线程不同步示例:
private static int count;
static void Main(string[] args)
{
Thread t1 = new Thread(TestFun);
t1.Name = "thread_1";
Thread t2 = new Thread(TestFun);
t2.Name = "thread_2";
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.ReadKey();
}
private static void TestFun()
{
while (count < 2)
{
count++;
count--;
Console.WriteLine(count);
Thread.Sleep(1);
}
}
输出结果:
我们期望的结果,肯定是输出一直都是0,但是以上代码,在执行了一定次数后,就会发生问题
在线程的方法中使用++或者–之类的操作都是线程不安全的
以++为例,它实际上是三步操作:
1)从内存中获取值
2)改变值的大小
3)存回内存中
这三步都有可能被线程调度器打断
所以这个时候,需要使用线程安全的方式,即Interlocked类
Interlocked类为多个线程共享的变量提供原子操作
把上面代码中的++和–操作,换成
Interlocked.Increment(ref count);
Interlocked.Decrement(ref count);
就不会出现上面的问题了
Mutex类:一个同步基元,也可用于进程间同步,这样只对一个线程授予对资源的独占访问
static void Main(string[] args)
{
Thread t1 = new Thread(TestFun);
t1.Name = "线程1";
Thread t2 = new Thread(TestFun);
t2.Name = "线程2";
Thread t3 = new Thread(TestFun);
t3.Name = "线程3";
Thread t4 = new Thread(TestFun);
t4.Name = "线程4";
t1.Start();
t2.Start();
t3.Start();
t4.Start();
Console.ReadKey();
}
private static void TestFun()
{
bool isNew;
using (Mutex m = new Mutex(false, "custom", out isNew))
{
Console.WriteLine(Thread.CurrentThread.Name + " " + (isNew ? "获取到了互斥量" : "未获取到互斥量"));
Thread.Sleep(1000);
}
}
SemaphoreSlim 类:对可同时访问资源或资源池的线程数加以限制
private static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static void Main(string[] args)
{
Thread t1 = new Thread(TestFun);
t1.Name = "线程1";
Thread t2 = new Thread(TestFun);
t2.Name = "线程2";
t1.Start();
t2.Start();
Console.ReadKey();
}
private static void TestFun()
{
Console.WriteLine("{0} Enter",Thread.CurrentThread.Name);
semaphore.Wait();
Console.WriteLine("{0} Start", Thread.CurrentThread.Name);
Thread.Sleep(2000);
semaphore.Release();
Console.WriteLine("{0} End", Thread.CurrentThread.Name);
}
我们这里限制了线程并发数为1,所以两个显示开始执行后,线程1开始执行逻辑,线程2在等待
两秒后线程1执行完毕,线程2开始执行
两秒后线程2执行完毕
都是一些预定义的类,实现线程同步的类还有很多,就不一一赘述了,这里就写几个比较基本的,来清晰概念。
我会在我的公众号上推送新的博文,也可以帮大家解答问题
微信公众号 Andy and Unity 搜索名称或扫描二维码
希望我们能共同成长,共同进步