WCF

管理,  WCF(Windows Communication
Foundation)是由微软开发的一密密麻麻援助数据通信的应用程序框架,可以翻译为Windows通信开发平台

1、概念

  WCF整合了原本的Windows通信的.net Remoting
,Web瑟维斯(Service),Socket机制,并融合有HTTP和FTP的相干技术。WCF是对这几个技能的联合。

  1.0 线程的和过程的关联以及优缺点**

WCF的优点

  windows系统是一个多线程的操作系统。一个主次至少有一个过程,一个过程至少有一个线程。进程是线程的容器,一个C#客户端程序先河于一个单独的线程,CLR(公共语言运行库)为该过程创立了一个线程,该线程称为主线程。例如当我们创立一个C#控制台程序,程序的入口是Main()函数,Main()函数是始于一个主线程的。它的效应重倘若爆发新的线程和推行顺序。C#是一门扶助多线程的编程语言,通过Thread类创制子线程,引入using
System.Threading命名空间。 

   统一性

多线程的助益 

   互操作性

1
2
1、 多线程可以提高CPU的利用率,因为当一个线程处于等待状态的时候,CPU会去执行另外的线程
2、 提高了CPU的利用率,就可以直接提高程序的整体执行速度

   安全与可凭借

多线程的缺点:

   兼容性

 

   

1
2
3
1、线程开的越多,内存占用越大
2、协调和管理代码的难度加大,需要CPU时间跟踪线程
3、线程之间对资源的共享可能会产生可不遇知的问题

精通面向服务

 

   SOA(瑟维斯(Service)(Service) Oriented Atchitecture)面向服务架构
 。是指为了解决在Internel环境下作业集成的急需,通过连续能不辱使命一定任务的独自功用实体实现的一种软件系统架构。SOA是一个零件模型,将应用程序的不比效率单元(称为服务)通过这个劳务中间定义卓绝的接口和契约关系起来

     1.1 前台线程和后台线程

 
 SOA提出如今系统应该充足灵活,从而允许在不打乱当前成功运行的系统布局和底蕴结构前提下,改动已有些连串布局。

   
 
C#中的线程分为前台线程和后台线程,线程创制时不做设置默认是前台线程。即线程属性IsBackground=false。

   SOA有如下原则

Thread.IsBackground = false;//false:设置为前台线程,系统默认为前台线程。

       边界清晰

 区别以及如何使用:

       服务自治

    这二者的界别就是:应用程序必须运行完所有的前台线程才可以退出;而对此后台线程,应用程序则可以不考虑其是否早已运行完毕而从来退出,所有的后台线程在应用程序退出时都会自行终止。一般后台线程用于拍卖时间较短的天职,如在一个Web服务器中可以使用后台线程来拍卖客户端发过来的哀告音信。而前台线程一般用于拍卖需要长日子等待的任务,如在Web服务器中的监听客户端请求的次序。

       包容性基于政策

线程是寄托在过程上的,进程都终止了,线程也就没有了!

       共享模式(schema)和契约

倘若有一个前台线程未脱离,进程就不会告一段落!即说的就是程序不会倒闭!(即在资源管理器中得以看来进程未截至。)

 

     1.3 多线程的创建

WCF框架组成

   
上面的代码创立了一个子线程,作为程序的入口mian()函数所在的线程即为主线程,咱们通过Thread类来创设子线程,Thread类有 ThreadStart 和
ParameterizedThreadStart类型的嘱托参数,我们也可以直接写方法的名字。线程执行的法子可以传递参数(可选),参数的类别为object,写在Start()里。

   1.协定(契约)

管理 1

     
契约来定义双方互换的协议,契约必须以接口的不二法门来反映,而实质上的服务代码必须要由这么些契约接口派生并贯彻,

class Program
 {
        //我们的控制台程序入口是main函数。它所在的线程即是主线程
        static void Main(string[] args)     
        {
            Thread thread = new Thread(ThreadMethod);     //执行的必须是无返回值的方法
            thread.Name = "子线程";
            //thread.Start("王建");                       //在此方法内传递参数,类型为object,发送和接收涉及到拆装箱操作
            thread.Start(); 
            Console.ReadKey();
        }

        public static void ThreadMethod(object parameter) //方法内可以有参数,也可以没有参数
        {
            Console.WriteLine("{0}开始执行。", Thread.CurrentThread.Name);
        }
  }

     契约可分为以下4种:

管理 2

       1.多少契约(Data
Contract):指定双方关系时的数据格式

首先使用new
Thread()创设出新的线程,然后调用Start方法使得线程进入就绪状态,得到系统资源后就实施,在推行进程中恐怕有等待、休眠、死亡和堵塞四种意况。正常履行完毕时间片后再次回到到就绪状态。假如调用Suspend方法会跻身等待状态,调用Sleep或者遭逢进程同步使用的锁机制而休眠等待。具体经过如下图所示:

       2.服务契约(瑟维斯(Service)(Service) Contract):指定服务的概念

管理 3

       3.操作契约(Opration Contract):指定服务提供的法门

2、线程的基本操作

       4.新闻契约(MessageContract):指定在通信期间改写音信内容的业内

线程和其他常见的类一样,有着广大性质和艺术,参考下表:

       契约定义音信系统的各种方面

管理 4

          (1).数据契约:服务中的参数

2.1 线程的有关属性

          (2).音信契约:使用SOAP协议一定的信息部分

大家得以经过地方表中的性质获取线程的一对连锁信息,下面是代码呈现和出口结果:

          (3).服务契约:服务中的方法

管理 5

         
(4).策略与绑定:策略设置安全或另外条件,绑定指定传输情势与编码。

static void Main(string[] args)     
        {
            Thread thread = new Thread(ThreadMethod);     //执行的必须是无返回值的方法
            thread.Name = "子线程"; 
            thread.Start();
            StringBuilder threadInfo = new StringBuilder();
            threadInfo.Append(" 线程当前的执行状态: " + thread.IsAlive);
            threadInfo.Append("\n 线程当前的名字: " + thread.Name);
            threadInfo.Append("\n 线程当前的优先级: " + thread.Priority);
            threadInfo.Append("\n 线程当前的状态: " + thread.ThreadState);
            Console.Write(threadInfo);
            Console.ReadKey();
        }

        public static void ThreadMethod(object parameter)  
        {
            Console.WriteLine("{0}开始执行。", Thread.CurrentThread.Name);
        }

   2.服务运行

管理 6

      服务运行期间的一言一行控制

 输输出结果: 管理 7

          (1).限制行为:控制处理的音讯数

2.2 线程的相关操作

          (2).错误行为:出现其中错误时所拍卖的操作

  2.2.1 Abort()方法

          (3).元数据作为:是否向外提供元数据及元数据的提供模式

     Abort()方法用来终止线程,调用此方法强制结束正在履行的线程,它会抛出一个ThreadAbortException分外从而致使目的线程的平息。上面代码演示:

          (4).实例行为:可运行的劳务实例数目

     

          (5).事务行为:处理事务

管理 8

          (6).调度行为:控制WCF处理信息的法子

static void Main(string[] args)     
        {
            Thread thread = new Thread(ThreadMethod);     //执行的必须是无返回值的方法 
            thread.Name = "小A";
            thread.Start();  
            Console.ReadKey();
        }

        public static void ThreadMethod(object parameter)  
        {
            Console.WriteLine("我是:{0},我要终止了", Thread.CurrentThread.Name);
            //开始终止线程
            Thread.CurrentThread.Abort();
            //下面的代码不会执行
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
            }
        }

   3.音讯传递

管理 9

     
 音讯传递层表明数据的互换格式和传导形式。音信传递层由通道(信道)组成,通道是对音信举行处理的零部件,负责以平等的点子对音信举办整治和传递。通道用于传输层,协议层及音讯得到。各层次的坦途组成了信道栈

实施结果:和我们想像的一致,下边的大循环没有被实施管理 10

     
 通道对信息和音信头举行操作,服务运行时对信息正文举办操作。通道包括两种档次:传输通道与商谈通道。

 

             
传输通道:读取和写入来自网络的消息,传输通道通过编码器将消息转换为网络传输使用的字节流以及将字节流转换为音讯。传输通道包括HTTP通道,命名管道,TCP,MSMQ等

  2.2.2 ResetAbort()方法

              协议通道:通过读取或写入消息头的点子来促成消息协议。比如
WS-Security。WS-Reliability

  
   Abort方法可以经过跑出ThreadAbortException很是中止线程,而接纳ResetAbort方法可以废除中止线程的操作,下面通过代码演示使用 ResetAbort方法。

   4.宿主与激活

管理 11

       
 服务宿主负责WCF服务的生命周期和上下文的操作系统进程,负责启动和终止WCF服务,并提供控制伏务的骨干管理效用。

     static void Main(string[] args)     
        {
            Thread thread = new Thread(ThreadMethod);     //执行的必须是无返回值的方法 
            thread.Name = "小A";
            thread.Start();  
            Console.ReadKey();
        }

        public static void ThreadMethod(object parameter)  
        {
            try
            {
                Console.WriteLine("我是:{0},我要终止了", Thread.CurrentThread.Name); 
         //开始终止线程
                Thread.CurrentThread.Abort();
            }
            catch(ThreadAbortException ex)
            {
                Console.WriteLine("我是:{0},我又恢复了", Thread.CurrentThread.Name);
         //恢复被终止的线程
                Thread.ResetAbort();
            }
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
            }
        }

 

管理 12

WCF的底子概念

实施结果:管理 13

     1.地址

  2.2.3 Sleep()方法 

      2.绑定(Binding)

      
Sleep()方法调已阻塞线程,是眼前线程进入休眠状态,在蛰伏过程中占有系统内存可是不占用系统时间,当休眠期过后,继续执行,阐明如下:
 

      3.契约(Contract)

        public static void Sleep(TimeSpan timeout);          //时间段
        public static void Sleep(int millisecondsTimeout);   //毫秒数

      4.终结点

  实例代码: 

       
 用来发送或接受消息(或施行这两种操作)的社团,终结点包含一个概念音信可以发送在的目标地地方节点,包含一个定义音讯可以发送到的目标地地方(地址),一个叙述信息应什么发送的通信机制正式(绑定)以及对此可以在该职务发送或收到(或双方皆可)的一组信息的定义(服务协定)—该定义还描述了足以发送何种音信

管理 14

       
终结点的地点由EndpointAddress类表示,该类包含一个表示服务地址额统一资源一定符(URI),大多数传输的地址URI包含4有的。

       static void Main(string[] args)
        {
            Thread threadA = new Thread(ThreadMethod);     //执行的必须是无返回值的方法 
            threadA.Name = "小A";
            threadA.Start();
            Console.ReadKey();
        } 
        public static void ThreadMethod(object parameter)  
        { 
            for (int i = 0; i < 10; i++)
            { 
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
                Thread.Sleep(300);         //休眠300毫秒              
            }
        }

     
 例:https://home.cnblogs.com/u/1147658/

管理 15

           方案:https

将方面的代码执行将来,可以知晓的观察每一趟循环之间相差300毫秒的时刻。

           计算机:home.cnblogs.com

      2.2.4 join()方法

           端口(可选):

    
 Join方法重假若用来阻塞调用线程,直到某个线程终止或通过了点名时间截至。官方的分解相比较单调,通俗的说就是创办一个子线程,给它加了这么些情势,另外线程就会暂停实施,直到这多少个线程执行完截止才去履行(包括主线程)。她的方法表明如下:

           路径:u/147658

 public void Join();
 public bool Join(int millisecondsTimeout);    //毫秒数
 public bool Join(TimeSpan timeout);       //时间段

      5.元数据

为了讲明方面所说的,我们首先看一段代码:  

      6.宿主(Host)

管理 16

static void Main(string[] args)
        {
            Thread threadA = new Thread(ThreadMethod);     //执行的必须是无返回值的方法 
            threadA.Name = "小A";
            Thread threadB = new Thread(ThreadMethod);     //执行的必须是无返回值的方法  
            threadB.Name = "小B";
            threadA.Start();
       //threadA.Join();      
            threadB.Start();
       //threadB.Join();

            for (int i = 0; i < 10; i++)
            { 
                Console.WriteLine("我是:主线程,我循环{1}次", Thread.CurrentThread.Name, i);
                Thread.Sleep(300);          //休眠300毫秒                                                
            }
            Console.ReadKey();
        } 
        public static void ThreadMethod(object parameter)  
        { 
            for (int i = 0; i < 10; i++)
            { 
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name,i);
                Thread.Sleep(300);         //休眠300毫秒              
            }
        }

管理 17

 

因为线程之间的履行是任意的,所有执行结果和我们想象的一律,杂乱无章!但是表明他俩是还要实施的。管理 18

     现在大家把代码中的
 ThreadA.join()方法注释裁撤,首先程序中有五个线程,ThreadA、ThreadB和主线程,首先主线程先阻塞,然后线程ThreadB阻塞,ThreadA先实施,执行完毕之后ThreadB接着执行,最终才是主线程执行。

看执行结果:

管理 19

        2.2.5 Suspent()和Resume()方法

       其实在C# 2.0以后,
Suspent()和Resume()方法已经不合时宜了。suspend()方法容易发生死锁。调用suspend()的时候,目的线程会停下来,但却仍然有着在这后面拿到的锁定。此时,其他任何线程都不可以访问锁定的资源,除非被”挂起”的线程恢复生机运行。对其他线程来说,假使它们想重操旧业目的线程,同时又打算动用任何一个锁定的资源,就会导致死锁。所以不应当使用suspend()。

 

管理 20

     static void Main(string[] args)
        {
            Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "小A";  
            threadA.Start();  
            Thread.Sleep(3000);         //休眠3000毫秒      
            threadA.Resume();           //继续执行已经挂起的线程
            Console.ReadKey();
        }
        public static void ThreadMethod(object parameter)
        {
            Thread.CurrentThread.Suspend();  //挂起当前线程
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i); 
            }
        }

管理 21

 

       执行下边的代码。窗口并不曾及时执行
ThreadMethod方法输出循环数字,而是等待了三分钟之后才输出,因为线程起先进行的时候实施了Suspend()方法挂起。然后主线程休眠了3分钟将来又经过Resume()方法復苏了线程threadA。

    2.2.6 线程的优先级

  即便在应用程序中有两个线程在运作,但一些线程比另一部分线程重要,这种情况下可以在一个经过中为不同的线程指定不同的先期级。线程的先期级可以通过Thread类Priority属性设置,Priority属性是一个ThreadPriority型枚举,列举了5个优先等级:AboveNormal、Below诺玛l、Highest、Lowest、诺玛l。公共语言运行库默认是诺玛(Norma)l类型的。见下图:

管理 22

一贯上代码来看效用:

管理 23

管理 24

static void Main(string[] args)
        {                
            Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "A";
            Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "B";
            threadA.Priority = ThreadPriority.Highest;
            threadB.Priority = ThreadPriority.BelowNormal;
            threadB.Start();
            threadA.Start();
            Thread.CurrentThread.Name = "C";
            ThreadMethod(new object());
            Console.ReadKey();
        }
        public static void ThreadMethod(object parameter)
        {
            for (int i = 0; i < 500; i++)
            { 
                Console.Write(Thread.CurrentThread.Name); 
            }
        }

管理 25

施行结果:

管理 26

地点的代码中有六个线程,threadA,threadB和主线程,threadA优先级最高,threadB优先级最低。那一点从运行结果中也足以看出,线程B
偶尔会并发在主线程和线程A前边。当有四个线程同时地处可进行情况,系统优先执行优先级较高的线程,但那只代表优先级较高的线程占有更多的CPU时间,并不代表一定要先实施完优先级较高的线程,才会实施优先级较低的线程。

优先级越高意味着CPU分配给该线程的年月片越多,执行时间就多

先行级越低表示CPU分配给该线程的时间片越少,执行时间就少

   3、线程同步

  什么是线程安全:

  线程安全是指在当一个线程访问该类的某个数据时,举办吝惜,其他线程不可能开展走访直到该线程读取完,其他线程才可应用。不会产出数量不均等或者数额污染。

   线程有可能和其余线程共享一些资源,比如,内存,文件,数据库等。当两个线程同时读写同一份共享资源的时候,可能会唤起争执。这时候,大家需要引入线程“同步”机制,即诸君线程之间要有个先来后到,不可以一窝蜂挤上去抢作一团。线程同步的忠实意思和字面意思恰好相反。线程同步的实际意思,其实是“排队”:多少个线程之间要排队,一个一个对共享资源举办操作,而不是同时展开操作。

怎么要实现共同啊,下边的例证我们拿著名的单例格局以来呢。看代码

管理 27

public class Singleton
    {
        private static Singleton instance; 
        private Singleton()   //私有函数,防止实例
        {

        } 
        public static Singleton GetInstance()
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }

管理 28

     
 单例格局就是确保在方方面面应用程序的生命周期中,在任什么日期刻,被指定的类唯有一个实例,并为客户程序提供一个取得该实例的全局访问点。但地方代码有一个强烈的题目,这就是一旦六个线程同时去赢得这些目的实例,这。。。。。。。。

我们队代码进行改动:

管理 29

public class Singleton
{
       private static Singleton instance;
       private static object obj=new object(); 
       private Singleton()        //私有化构造函数
       {

       } 
       public static Singleton GetInstance()
       {
               if(instance==null)
               {
                      lock(obj)      //通过Lock关键字实现同步
                      {
                             if(instance==null)
                             {
                                     instance=new Singleton();
                             }
                      }
               }
               return instance;
       }
}

管理 30

由此改动后的代码。加了一个
lock(obj)代码块。这样就可以实现协同了,假若不是很精通的话,大家看前边继续助教~

  3.0 使用Lock关键字贯彻线程同步 

  率先成立四个线程,多少个线程执行同一个主意,参考下边的代码:

管理 31

static void Main(string[] args)
        {
            Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "王文建";
            Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "生旭鹏";
            threadA.Start();
            threadB.Start();
            Console.ReadKey();
        }
        public static void ThreadMethod(object parameter)
        { 
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
                Thread.Sleep(300);
            }
        }

管理 32

施行结果:

管理 33

 

透过上边的举行结果,可以很领悟的看来,六个线程是在同时履行ThreadMethod那个主意,这明确不切合我们线程同步的渴求。我们对代码举办修改如下:

管理 34

管理 35

static void Main(string[] args)
        {
            Program pro = new Program();
            Thread threadA = new Thread(pro.ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "王文建";
            Thread threadB = new Thread(pro.ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "生旭鹏";
            threadA.Start();
            threadB.Start();
            Console.ReadKey();
        }
        public void ThreadMethod(object parameter)
        {
            lock (this)             //添加lock关键字
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
                    Thread.Sleep(300);
                }
            } 
        }

管理 36

施行结果:

管理 37

我们通过添加了 lock(this)
{…}代码,查看执行结果实现了大家想要的线程同步要求。不过我们了然this表示目前类实例的本人,那么有这般一种情景,大家把需要拜访的法子所在的类型举行七个实例A和B,线程A访问实例A的办法ThreadMethod,线程B访问实例B的办法ThreadMethod,这样的话还是可以达标线程同步的急需呢。

管理 38

管理 39

static void Main(string[] args)
        {
            Program pro1 = new Program();                    
            Program pro2 = new Program();                   
            Thread threadA = new Thread(pro1.ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "王文建";
            Thread threadB = new Thread(pro2.ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "生旭鹏";
            threadA.Start();
            threadB.Start();
            Console.ReadKey();
        }
        public void ThreadMethod(object parameter)
        {
            lock (this)
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
                    Thread.Sleep(300);
                }
            }
        }

管理 40

施行结果:

管理 41

我们会发现,线程又从不兑现同台了!lock(this)对于这种意况是至极的!所以需要大家对代码举办改动!修改后的代码如下: 

管理 42

管理 43

private static object obj = new object();
        static void Main(string[] args)
        {
            Program pro1 = new Program();                    
            Program pro2 = new Program();                   
            Thread threadA = new Thread(pro1.ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "王文建";
            Thread threadB = new Thread(pro2.ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "生旭鹏";
            threadA.Start();
            threadB.Start();
            Console.ReadKey();
        }
        public void ThreadMethod(object parameter)
        {
            lock (obj)
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("我是:{0},我循环{1}次", Thread.CurrentThread.Name, i);
                    Thread.Sleep(300);
                }
            }
        }

管理 44

透过查看执行结果。会发现代码实现了俺们的急需。那么 lock(this)
和lock(Obj)有如何区别吗? 

lock(this) 锁定 当前实例对象,如果有多个类实例的话,lock锁定的只是当前类实例,对其它类实例无影响。所有不推荐使用。 
lock(typeof(Model))锁定的是model类的所有实例。 
lock(obj)锁定的对象是全局的私有化静态变量。外部无法对该变量进行访问。 
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。 
所以,lock的结果好不好,还是关键看锁的谁,如果外边能对这个谁进行修改,lock就失去了作用。所以一般情况下,使用私有的、静态的并且是只读的对象。

总结:

1、lock的是必须是援引类型的对象,string类型除外。

2、lock推荐的做法是拔取静态的、只读的、私有的对象。

3、保证lock的靶子在表面不能修改才有含义,假诺lock的目的在外表改变了,对其他线程就会通行,失去了lock的含义。

*     不可以锁定字符串,锁定字符串尤其危险,因为字符串被集体语言运行库
(CLR)“暂留”。
这代表任何程序中任何给定字符串都只有一个实例,就是这同一个对象表示了装有运行的应用程序域的保有线程中的该文件。由此,只要在应用程序进程中的任何地方处具有相同内容的字符串上停放了锁,就将锁定应用程序中该字符串的富有实例。平时,最好制止锁定
public
类型或锁定不受应用程序控制的对象实例。例如,假使该实例可以被公开访问,则
lock(this)
可能会有题目,因为不受控制的代码也说不定会锁定该目标。这可能导致死锁,即多个或更两个线程等待释放同一对象。出于同样的来由,锁定公共数据类型(对比于对象)也可能导致问题。而且lock(this)只对眼前目的有效,要是五个对象期间就达不到一道的法力。lock(typeof(Class))与锁定字符串一样,范围太广了。*

  3.1 使用Monitor类实现线程同步      

     
Lock关键字是Monitor的一种替换用法,lock在IL代码中会被翻译成Monitor. 

     lock(obj)

              {
                 //代码段
             } 
    就同一 
    Monitor.Enter(obj); 
                //代码段
    Monitor.Exit(obj);  

           Monitor的常用属性和方法:

    Enter(Object) 在指定对象上拿到排他锁。

    Exit(Object) 释放指定对象上的排他锁。 

 

    Pulse 通知等待队列中的线程锁定目的情形的改观。

    PulseAll 布告所有的等待线程对象情形的改变。

    TryEnter(Object) 试图获取指定对象的排他锁。

    TryEnter(Object,
Boolean)
 尝试得到指定对象上的排他锁,并自动安装一个值,提示是否得到了该锁。

    Wait(Object) 释放对象上的锁并阻止当前线程,直到它再也取得该锁。

     
常用的措施有六个,Monitor.Enter(object)方法是赢得锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的多少个艺术,在接纳过程中为了制止获取锁之后因为相当,致锁不可以自由,所以需要在try{}
catch(){}之后的finally{}结构体中放出锁(Monitor.Exit())。

Enter(Object)的用法很粗略,看代码 

管理 45

     static void Main(string[] args)
        {                
            Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "A";
            Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "B";
            threadA.Start();
            threadB.Start();
            Thread.CurrentThread.Name = "C";
            ThreadMethod();
            Console.ReadKey();
        }
        static object obj = new object();
        public static void ThreadMethod()
        {
            Monitor.Enter(obj);      //Monitor.Enter(obj)  锁定对象
            try
            {
                for (int i = 0; i < 500; i++)
                {
                    Console.Write(Thread.CurrentThread.Name); 
                }
            }
            catch(Exception ex){   }
            finally
            { 
                Monitor.Exit(obj);  //释放对象
            } 
        } 

管理 46

 

TryEnter(Object)TryEnter() 方法在尝试得到一个目的上的显式锁方面和
Enter()方法类似。但是,它不像Enter()方法这样会堵塞执行。假若线程成功跻身关键区域那么TryEnter()方法会再次回到true. 和总括拿走指定对象的排他锁。看下面代码演示:

      我们得以经过Monitor.TryEnter(monster,
1000),该办法也可以防止死锁的暴发,我们下面的例子用到的是该模式的重载,Monitor.TryEnter(Object,Int32),。 

管理 47

static void Main(string[] args)
        {                
            Thread threadA = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadA.Name = "A";
            Thread threadB = new Thread(ThreadMethod); //执行的必须是无返回值的方法 
            threadB.Name = "B";
            threadA.Start();
            threadB.Start();
            Thread.CurrentThread.Name = "C";
            ThreadMethod();
            Console.ReadKey();
        }
        static object obj = new object();
        public static void ThreadMethod()
        {
            bool flag = Monitor.TryEnter(obj, 1000);   //设置1S的超时时间,如果在1S之内没有获得同步锁,则返回false
        //上面的代码设置了锁定超时时间为1秒,也就是说,在1秒中后,
       //lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁
            try
            {
                if (flag)
                {
                    for (int i = 0; i < 500; i++)
                    {
                        Console.Write(Thread.CurrentThread.Name); 
                    }
                }
            }
            catch(Exception ex)
            {

            }
            finally
            {
                if (flag)
                    Monitor.Exit(obj);
            } 
        } 

管理 48

 Monitor.Wait和Monitor()Pause()

Wait(object)方法:释放对象上的锁并阻止当前线程,直到它再度取得该锁,该线程进入等待队列。
 Pulse方法:唯有锁的此时此刻主人可以行使 Pulse 向等待对象发出信号,当前有着指定对象上的锁的线程调用此格局以便向队列中的下一个线程发出锁的信号。接收到脉冲后,等待线程就被活动到就绪队列中。在调用 Pulse 的线程释放锁后,就绪队列中的下一个线程(不自然是接受到脉冲的线程)将收获该锁。
另外

        Wait 和 Pulse 方法必须写在 Monitor.Enter
和Moniter.Exit 之间。

地方是MSDN的分解。不知情看代码:

 首先我们定义一个攻击类,

管理 49

/// <summary>
    /// 怪物类
    /// </summary>
    internal class Monster
    {
        public int Blood { get; set; }
        public Monster(int blood)
        {
            this.Blood = blood;
            Console.WriteLine("我是怪物,我有{0}滴血",blood);
        }
    }

管理 50

接下来在概念一个攻击类

管理 51

/// <summary>
    /// 攻击类
    /// </summary>
    internal class Play
    {
        /// <summary>
        /// 攻击者名字
        /// </summary>
        public string Name { get; set; } 
        /// <summary>
        /// 攻击力
        /// </summary>
        public int Power{ get; set; }
        /// <summary>
        /// 法术攻击
        /// </summary>
        public void magicExecute(object monster)
        {
            Monster m = monster as Monster;
            Monitor.Enter(monster);
            while (m.Blood>0)
            {
                Monitor.Wait(monster);
                Console.WriteLine("当前英雄:{0},正在使用法术攻击打击怪物", this.Name);
                if(m.Blood>= Power)
                {
                    m.Blood -= Power;
                }
                else
                {
                    m.Blood = 0;
                }
                Thread.Sleep(300);
                Console.WriteLine("怪物的血量还剩下{0}", m.Blood);
                Monitor.PulseAll(monster);
            }
            Monitor.Exit(monster);
        }
        /// <summary>
        /// 物理攻击
        /// </summary>
        /// <param name="monster"></param>
        public void physicsExecute(object monster)
        {
            Monster m = monster as Monster;
            Monitor.Enter(monster);
            while (m.Blood > 0)
            {
                Monitor.PulseAll(monster);
                if (Monitor.Wait(monster, 1000))     //非常关键的一句代码
                {
                    Console.WriteLine("当前英雄:{0},正在使用物理攻击打击怪物", this.Name);
                    if (m.Blood >= Power)
                    {
                        m.Blood -= Power;
                    }
                    else
                    {
                        m.Blood = 0;
                    }
                    Thread.Sleep(300);
                    Console.WriteLine("怪物的血量还剩下{0}", m.Blood);
                }
            }
            Monitor.Exit(monster);
        }
    }

管理 52

实施代码:

管理 53

    static void Main(string[] args)
        {
            //怪物类
            Monster monster = new Monster(1000);
            //物理攻击类
            Play play1 = new Play() { Name = "无敌剑圣", Power = 100 };
            //魔法攻击类
            Play play2 = new Play() { Name = "流浪法师", Power = 120 };
            Thread thread_first = new Thread(play1.physicsExecute);    //物理攻击线程
            Thread thread_second = new Thread(play2.magicExecute);     //魔法攻击线程
            thread_first.Start(monster);
            thread_second.Start(monster);
            Console.ReadKey();
        }

管理 54

出口结果:

管理 55

总结:

  第一种状态:

  1. thread_first首先取得同步对象的锁,当执行到 Monitor.Wait(monster);时,thread_first线程释放自己对联合对象的锁,流放自己到等候队列,直到自己重新取得锁,否则一贯不通。
  2. 而thread_second线程一开首就竞争同步锁所以处于就绪队列中,这时候thread_second直接从稳妥队列出来得到了monster对象锁,起始实践到Monitor.PulseAll(monster)时,发送了个Pulse信号。
  3. 这时候thread_first接收到信号进入到妥善状态。然后thread_second继续往下举办到
    Monitor.Wait(monster,
    1000)时,这是一句非常首要的代码,thread_second将自己放逐到等候队列并释放自我对同步锁的垄断,该等待安装了1S的超时值,当B线程在1S以内没有再一次获拿到锁自动添加到就绪队列。
  4. 这时thread_first从Monitor.Wait(monster)的梗塞停止,再次回到true。起先举行、打印。执行下一行的Monitor.Pulse(monster),这时候thread_second如若1S的时间还没过,thread_second接收到信号,于是将团结添加到就绪队列。
  5. thread_first的联手代码块截至之后,thread_second再度拿到执行权, Monitor.Wait(m_smplQueue,
    1000)重回true,于是继续从该代码处往下实施、打印。当再度实施到Monitor.Wait(monster,
    1000),又起来了步子3。
  6. 梯次轮回。。。。

 
 第二种状况:thread_second首先拿到同步锁对象,首先实施到Monitor.PulseAll(monster),因为程序中没有索要拭目以待信号进入就绪状态的线程,所以这一句代码没有意思,当执行到 Monitor.Wait(monster,
1000),自动将自己放逐到等候队列并在这边阻塞,1S
时间将来thread_second自动添加到就绪队列,线程thread_first得到monster对象锁,执行到Monitor.Wait(monster);时发出阻塞释放同步对象锁,线程thread_second执行,执行Monitor.PulseAll(monster)时通知thread_first。于是又开首率先种情状…

Monitor.Wait是让眼前进程睡眠在临界资源上并释放独占锁,它只是等待,并不脱离,当等待截至,就要继续执行剩下的代码。

 

  3.0 使用Mutex类实现线程同步

   
  Mutex的崛起特点是足以跨应用程序域边界对资源拓展垄断访问,即可以用于共同不同进程中的线程,这种功用本来那是以牺牲更多的系统资源为代价的。

  首要常用的两个点子:

 public virtual bool WaitOne()   阻止当前线程,直到当前
System.Threading.WaitHandle 收到信号获取互斥锁。

 public void ReleaseMutex()     释放 System.Threading.Mutex 一次。

  使用实例:

管理 56

    static void Main(string[] args)
        {
            Thread[] thread = new Thread[3];
            for (int i = 0; i < 3; i++)
            {
                thread[i] = new Thread(ThreadMethod1);
                thread[i].Name = i.ToString();
            }
            for (int i = 0; i < 3; i++)
            {
                thread[i].Start();
            }
            Console.ReadKey(); 
        } 

        public static void ThreadMethod1(object val)
        {
            mutet.WaitOne();    //获取锁
            for (int i = 0; i < 500; i++)
            {
                Console.Write(Thread.CurrentThread.Name); 
            } 
            mutet.ReleaseMutex();  //释放锁
        }

管理 57

 2、线程池

   
  上边介绍了介绍了平常利用的大多数的多线程的例子,但在骨子里开发中采用的线程往往是大气的和更加复杂的,这时,每一回都创建线程、启动线程。从性能上来讲,这样做并不地道(因为每使用一个线程就要创制一个,需要占用系统开发);从操作上来讲,每趟都要开动,相比较辛勤。为此引入的线程池的概念。

  好处:

  1.缩减在创制和销毁线程上所花的年月以及系统资源的开销 
 
2.如不使用线程池,有可能造成系统创建大气线程而导致消耗完系统内存以及”过度切换”。

在怎么着状态下使用线程池? 

    1.单个任务处理的时光相比短 
    2.需要处理的职责的数据大 

线程池最多管理线程数量=“处理器数 *
250”。也就是说,假设你的机械为2个2核CPU,那么CLR线程池的容量默认上限便是1000

经过线程池创造的线程默认为后台线程,优先级默认为诺玛(Norma)l。

代码示例:

管理 58

    static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod1), new object());    //参数可选
            Console.ReadKey();
        }

        public static void ThreadMethod1(object val)
        { 
            for (int i = 0; i <= 500000000; i++)
            {
                if (i % 1000000 == 0)
                {
                    Console.Write(Thread.CurrentThread.Name);
                } 
            } 
        }

管理 59

 

 

有关线程池的表明请参考:

http://www.cnblogs.com/JeffreyZhao/archive/2009/07/22/thread-pool-1-the-goal-and-the-clr-thread-pool.html

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注