线程同步问题:
线程同步问题就是解决多个线程同时操作一个资源的问题
看下面一个例子:
private static int num = 0;
static void Main(string[] args)
{
Thread th1 = new Thread(() => {
for (int i = 0; i < 100; i++)
{
num++;
Thread.Sleep(1);
}
});
th1.Start();
Thread th2 = new Thread(() => {
for (int i = 0; i < 100; i++)
{
num++;
Thread.Sleep(1);
}
});
th2.Start();
Thread.Sleep(1000);
Console.WriteLine(num);
Console.ReadKey();
}
我们的理想状态是 200,但事与愿违,每次执行的结果都不同。因为线程执行需要时间,当th1线程执行时,th2线程同样在执行,但是这两个线程有个先后顺序。比如 th1先执行,th2后执行,现在num=100,当th1线程正要操作时,但还没来得及操作时,th2线程已经操作了num=102或其他值,而th1线程读入的值还是100,th1执行后又把值改为101了。当两个线程同时操作一个资源时候,就需要线程同步执行。
解决方法:
使用线程的 IsAlive 属性 或 Join()方法。但时尽量使用Join()方法。
private static int countec = 0;
static void Main(string[] args)
{
Thread t1 = new Thread(() =>
{
for (int i = 0; i < 1000; i++)
{
countec++; //自增1000次
Thread.Sleep(1);
}
});
t1.Start();
t1.Join();
Thread t2 = new Thread(() =>
{
for (int i = 0; i < 1000; i++)
{
countec++; //自增1000次
Thread.Sleep(1);
}
});
t2.Start();
//while (t1.IsAlive) { }; //死循环,等t1线程结束
//while (t2.IsAlive) { };//IsAlive: 如果此线程已启动并且尚未正常终止或中止,则为 true;否则为 false。
//while (t1.IsAlive) ;操作会大量消耗cpu空转,可以改成t1.Join()就是让当前线程等待t1线程的结束。
t2.Join();
Console.WriteLine(countec); //理想的值是:2000,但每次的值都不一样
//原因:线程执行是需要时间的 比如,当t1 加到150栋的时候,t2才加到100,t2又把100赋值给countec变量
Console.ReadKey();
}
要避免同步问题,最好不要在线程之间共享数据。当然,在现实开发中并不总是可行的。如果需要共享数据,就必须使用同步技术。确保一次只能有一个线程访问和改变共享状态。注意,同步问题与争用条件和死锁有关。如果不注意这些问题,就很难再程序中找到原因,因为线程的问题时不定期发生的。
关于.NET 中多线程的技术大概有:
- lock 语句
- Interlocked 类
- Monitor 类
- Spinlock 结构
- WaitHandle 类
- Mutex 类
- Semaphore 类
- Event 类
- Barrier 类
- ReaderWriterLockSlim 类
lock 语句 ,Interlocked 类,Monitor 类可以用于进程内部的同步。Mutex 类,Semaphore 类,Event 类和 ReaderWriterLockSlim 类提供了多个进程之间的线程同步。