同步线程:
.NET组件(类)默认在一多线程环境执行,可通过并发多线程访问,但可能导致对象状态破坏。想要该对象线程安全,就应确保一次只有一个线程可访问该对象。
自动同步:
//&-&看不懂,后补
手动同步:.NET手动同步提供了丰富的同步锁。
1.监视器(Monitor):设计成只和引用类型一同工作的锁。
private class MyClass
{
private int m_Number;
public int Number
{
get
{
//finally语句块在返回命令后执行,没必要使用临时变量保证线程安全了
lock(typeof(MyClass)){ return m_Number; }
}
}
//在方法内部封装Monitor促进松耦合和线程安全
public void DoSomething()
{
//C#提供了lock语句实际编译为以下语句
//lock(typeof(MyClass)){ ... }
//请求锁并锁定对象
//其他线程在请求该对象时,会被阻塞,直到调用Exit解除锁
//多个未决线程会放入锁队列中,依次获得服务
Monitor.Enter(typeof(MyClass));
try
{
Thread.Sleep(3000);
Console.Write(Thread.CurrentThread.Name + "线程执行完毕");
}
finally
{
//为对象解锁
Monitor.Exit(typeof(MyClass));
}
}
}
//调用
MyClass mc = new MyClass();
Thread threadA = new Thread(mc.DoSomething);
threadA.Name = "threadA";
Thread threadB = new Thread(mc.DoSomething);
threadB.Name = "threadB";
threadA.Start();
threadB.Start();
线程安全的结构:由于结构是值类型,那就不能把结构本身传递给Monitor,可以给结构中加以object类型成员变量,专用于Monitor。
//线程安全的结构
private struct MyStruct
{
/* 用于锁的引用对象 */
private object m_Lock;
//这个字段是来打酱油的^-^
private int m_Number;
//构造函数
public MyStruct(int number)
{
m_Lock = new object();
m_Number = number;
}
public void DoSomething()
{
/* 因为结构不一定会调用构造函数初始化,需检查m_Lock是否为null */
//Debug.Assert(m_Lock != null);
lock(m_Lock)
{
Thread.Sleep(3000);
Console.WriteLine(Thread.CurrentThread.Name + "线程执行完毕");
}
}
public void DoSomething2()
{
/* 因为结构不一定会调用构造函数初始化,需检查m_Lock是否为null */
//Debug.Assert(m_Lock != null);
lock (m_Lock)
{
Console.WriteLine(Thread.CurrentThread.Name + "线程执行完毕");
}
}
/* 深度拷贝 */
//考虑到将当前结构 = 给另一结构,只会浅拷贝,对于结构中引用类型m_Lock会被多个结构共享
//导致一个结构锁定,其他=的结构也都锁定
//因此附加一深拷贝方法
public MyStruct Clone()
{
MyStruct clone = new MyStruct(m_Number);
return clone;
}
}
//调用
MyStruct struct1 = new MyStruct(3);
//MyStruct struct2 = struct1;
MyStruct struct2 = struct1.Clone();
Thread threadA = new Thread(struct1.DoSomething);
threadA.Name = "threadA";
Thread threadB = new Thread(struct2.DoSomething2);
threadB.Name = "threadB";
threadA.Start();
//主线程挂起一定时间,为了保证threadA线程先锁定m_Lock对象
Thread.Sleep(100);
threadB.Start();
Monitor和泛型
//泛型类型安全锁定
public class MyClass<T>
{
T m_T;
public void DoSomething()
{
//因为泛型T可以为任何类型(值类型),除非限定T泛型类型
//最好锁定整个对象
lock(this)
{ ... }
}
}
碎片锁定:按需将锁定代码和未锁定代码混搭,但该模式是一个非常沉重的负担,容易导致代码错误。
因避免碎片锁定,而在整个方法中锁定对象。
//碎片锁定
public void DoSomething()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(i);
}
lock (this)
{
Console.WriteLine("d");
}
}
同步方法:相当于用一个lock语句包围整个方法。
using System.Runtime.CompilerServices;
//MethodImpl特性,也可以用于属性
[MethodImpl(MethodImplOptions.Synchronized)]
public void DoSomething()
{
/* 代码 */
}
//以上等同于下列代码
//public void DoSomething()
//{
// lock(this)
// {
// /* 代码 */
// }
//}
Monitor等待和发送信号
wait()释放锁并等待另一个线程调用Monitor。