线程同步即线程间对于CPU资源的协调,一次只有一个线程占用资源。进行线程同步的方法:
1.线程1调用方法,线程2在运行结束后调用Resume()方法唤醒工作线程,此方法需借助Sleep()方法协调时间,不灵活。容易出问题,比如线程1还没有Suspend(),线程2就Resume();或者后台进程还未运行,前台进程就结束了。
2.使用System.Threading.Monitor的Lock语句,调整Lock的颗粒度,即可得到想要的线程工作顺序(两个线程交替输出、顺位输出)。通过创建一个对象,实现对上锁(Enter())开锁(Exit())的目的,对象或者是object类型或是type类型。上述方法无法指定线程间的工作顺序,需要引入信号的概念来实现,原理类似1中的Suspend()和Resume()方法。Monitor中,有Wait()和Pulse()方法。原理很简单,线程1用Wait()方法等待线程2,线程2做完工作用Pulse()方法知会线程1,“我做完了”,线程1继续执行自己的下一步。
3.使用System.Threading.WaitHandle旗下的Mutex类可以帮助简化上锁的过程,它可以替代为了上锁而创建的锁对象。
委托用于调用一个方法,通过委托进行异步调用时,往往是从线程池抓取线程执行,随用随取。运用BeginInvoke()和EndInvoke()的方法实现。以下为一个示例:两个线程运行,主线程在static void Main里面,线程池线程执行Calculator方法里的程序。
class Program
{
public delegate int AddDelegate(int x,int y);
static void Main(string[] args)
{
Console.WriteLine("Task started!");
Thread.CurrentThread.Name = "Main Thread";
Calculator cal = new Calculator();
AddDelegate del = new AddDelegate(cal.Add);//异步调用方法Add
AsyncCallback callback = new AsyncCallback(GetReturn);//不再使用EndIncoke,而使用回调函数,当异步方法结束后自动打印结果
string data = "吃麻辣烫";
IAsyncResult asyresult = del.BeginInvoke(2, 5, callback, data);
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine("主线程干活");
//int result = del.EndInvoke(asyresult);//通过IAsyncResult接口得到结果。
Console.WriteLine("the current thread is {0} ",Thread.CurrentThread.Name);
Console.ReadKey();
}
static void GetReturn(IAsyncResult asyresult)
{
AsyncResult result = (AsyncResult)asyresult;//将IAsyncResult类型转换成实际的类型AsyncResult,才能使用AsyncDelegate
AddDelegate del = (AddDelegate)result.AsyncDelegate;
//AddDelegate del = (AddDelegate)result.AsyncDelegate;
string data = (string)result.AsyncState;//get the object of BeginInvoke
int rtn = del.EndInvoke(asyresult);
Console.WriteLine("the result is {0}; Data: {1}", rtn,data);
}
public class Calculator
{
public int Add(int x,int y)
{
Console.WriteLine("Method Invoked");
if (Thread.CurrentThread.IsThreadPoolThread)
{
Thread.CurrentThread.Name = "Pool Thread";
}
Thread.Sleep(TimeSpan.FromSeconds(3));//线程池方法持续3s
Console.WriteLine("the current thread is {0}, Method complete!",Thread.CurrentThread.Name);
int result = x + y;
return result;
}
}
//int result = del.EndInvoke(asyresult)在第26行,紧接着beginInvoke,则程序全程消耗7s。
//如果该语句在30行,当主线程工作时间大于线程池,线程池先工作,反之,主线程先工作,总工作时长为两者最大值;
}
4. 发布者和订阅者
发布者的事件C通过委托绑定订阅者中的方法A,并在其内通过一个方法B激活事件C,从而执行方法A。
发布者和订阅者之间的关系是松耦合的,大多数情况下,它不关心订阅者执行的结果,除非异常处理时,需要及时止损。
5.Observer设计模式
这里的例子就是热水壶烧水,在到了快到100度的时候,显示器提示当前温度,到了100度是,显示烧开了。观察者是显示器,被观察者是热水壶。
推模式:将热水壶的温度变量封装为data(e),通过Notify()方法,使得显示器的值实时更新
拉模式:直接将显示器向下转换,作为obj传递出去。这时为了访问温度,需要为温度变量创建一个公共属性,使得在程序中其它位置也可以修改温度变量,增加了风险。
推模式就像是通过密码新传递情报,而拉模式就像是特工本人出面口头传递,显然暴露的可能性更大。
这两种模式都通过Notify()方法,传递给Update()方法,后者从属于观察者,一手e,一手obj,这就是事件的来源了。