zoukankan      html  css  js  c++  java
  • C#当中的多线程_线程基础

    前言

    最近工作不是很忙,想把买了很久了的《C#多线程编程实战》看完,所以索性把每一章的重点记录一下,方便以后回忆。

    1 线程基础

    1.创建一个线程

    using System;
    
    using System.Threading;
    
    namespace Chapter1.Recipe1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Thread t = new Thread(PrintNumbers);
    
                t.Start();
    
                PrintNumbers();
            }
    
            static void PrintNumbers()
            {
                Console.WriteLine("Starting...");
    
                for (int i = 1; i < 10; i++)
                {
                    Console.WriteLine(i);
                }
            }
        }
    }

    2.改变线程状态的方法

    ①线程暂停-Sleep()方法

    它是Thread类中的一个静态方法,使用方式是Thread.Sleep(timeout);

     

    ②线程等待-Join()方法

    它是线程实例的一个实例方法,使用时t.Join();(t是线程的一个实例)

    说明:该方法允许我们等待直到线程t完成,当t执行完成后,主线程会继续执行。借助这个方法可以简单实现两个线程之间的同步执行顺序。第一个线程会等第二个线程执行完成后再继续执行。此时第一个线程处于阻塞状态。

     

    ③终止线程-Abort()方法

    它也是一个实例方法,使用方法是t.Abort()

    说明:它终止线程的方法是给线程注入一个ThreadAbortException,导致线程被终结。这个异常可能会导致程序的彻底崩溃。并且这个异常并不一定会终止线程,目标线程可以通过处理该异常并调用Thread.ResetAbort方法来拒绝终止线程。终止线程的方法最好是通过添加一个标志来进行线程的终止。

     

    ④检查线程的状态-ThreadState

    ThreadState是一个枚举类型,包含了线程运行的几种状态。

     

    ⑤线程的优先级

    ThreadPriority也是一个枚举类型   

     public enum ThreadPriority
     {
            Lowest = 0,
            BelowNormal = 1,
            Normal = 2,
            AboveNormal = 3,
            Highest = 4,
     }

    使用方法:

    threadOne.Priority = ThreadPriority.Highest;

     

    ⑥前台线程和后台线程

    IsBackground属性用来区别前台线程和后台线程,默认情况下创建的线程都是前台线程,当把线程的属性IsBackground设置为true的时候,那么则创建一个后台线程。

    前台线程和后台线程的区别:进程会等待所有的前台线程执行完之后再去结束,如果只剩下了后台线程则进程会直接结束。

     

    ⑦向线程传递参数

    方式一:

    定义一个类,在类的构造函数当中进行参数的赋值

    1  class ThreadSample
    2  {
    3      private readonly int _iterations;
    4
    5      public ThreadSample(int iterations)
    6      {
    7          iterations = iterations;
    8      }
    9      public void CountNumbers()
    10     {
    11         for (int i = 1; i <= _iterations; i++)
    12         {
    13             Thread.Sleep(TimeSpan.FromSeconds(0.5));
    14             Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);
    15         }
    16     }
    17

    调用:

    1       var sample = new ThreadSample(10);
    
    2       var threadOne = new Thread(sample.CountNumbers);
    
    3       threadOne.Name = "ThreadOne";
    
    4       threadOne.Start();
    
    5       threadOne.Join();
    

    方式二:采用ParameterizedThreadStart的方式

       ParameterizedThreadStart是一个委托类型,接收一个object类型的参数。

       public delegate void ParameterizedThreadStart(object obj);

    使用方法:

    Count函数有一个object类型的参数

    1         static void Count(object iterations)
    2         {
    3             CountNumbers((int)iterations);
    4         }
    5
    
    6         static void CountNumbers(int iterations)
    7         {
    8             for (int i = 1; i <= iterations; i++)
    9             {
    10                 Thread.Sleep(TimeSpan.FromSeconds(0.5));
    11                 Console.WriteLine("{0} prints {1}", Thread.CurrentThread.Name, i);
    12             }
    13         }

    调用:

    1  ParameterizedThreadStart paramThread = new ParameterizedThreadStart(Count);
    2  Thread threadMy = new Thread(paramThread);
    3  threadMy.Name = "My";
    4  threadMy.Start(10);
    5  threadMy.Join(); 

    方式三:采用lambda表达式

    1 var threadThree = new Thread(() => CountNumbers(12));
    2 threadThree.Name = "ThreadThree";
    3 threadThree.Start();
    4 threadThree.Join(); 

    () => CountNumbers(12) lambda表达式定义了一个不属于任何类的方法。我们创建了一个方法,该方法使用需要的参数调用了另一个方法,并在另一个线程中运行该方法。

     

    lock关键字

    lock关键字来解决线程之间的竞争条件。

    在C# lock关键字定义如下: lock(expression) statement_block,其中expression代表你希望跟踪的对象,通常是对象引用。

    代码示例如下:

            private static object  ojb = new object();

            lock(obj)

            {

                     //锁定运行的代码段

            }

    假设线程A先执行,线程B稍微慢一点。线程A执行到lock语句,判断obj是否已申请了互斥锁,判断依据是逐个与已存在的锁进行object.ReferenceEquals比较(此处未加证实),如果不存在,则申请一个新的互斥锁,这时线程A进入lock里面了。

     

    Monitor类锁定资源

    这个类用来避免死锁,之前的lock关键字用来创建死锁,其实lockMonitor的一个语法糖

    首先lockMinitor有什么区别呢?

     

    Monitor和Lock的区别

    1.LockMonitor的语法糖。

    2.Lock只能针对引用类型加锁。

    3.Monitor能够对值类型进行加锁,实质上是Monitor.Enter(object)时对值类型装箱。

    4.Monitor还有其他的一些功能。

     

    貼り付け元  <http://www.cnblogs.com/chengxingliang/p/3150731.html>

     

    其实lockIL代码中会被翻译成Monitor。也就是Monitor.Enter(obj)Monitor.Exit(obj).

    lockobj

    {

    }

    等价为:

    try

    {    

          Monitor.Enter(obj) 

    }

    catch()

    {}

    finally

    {

          Monitor.Exit(obj) 

    }

    所以lock能做的,Monitor肯定能做,Monitor能做的,lock不一定能做。那么Monitor额外的功能呢?

     

    1Monitor.TryEnter(obj,timespan)----timeout之后,就不执行这段代码了。lock可是一直会死等的。

     

    2:还有Monitor.Wait()Monitor.Pulse()。在lock代码里面如果调用了Monitor.Wait(),会放弃对资源的所有权,让别的线程lock进来。然后别的线程代码里Pulse一下(让原线程进入到等待队列),然后在Wait一下释放资源,这样原线程的就可以继续执行了(代码还堵塞在wait那句话呢)。

    也就是说,必须两个或多个线程共同调用WaitPulse,把资源的所有权抛来抛去,才不会死锁。

     

    Monitor的常用属性和方法:

    Enter(Object) 在指定对象上获取排他锁。

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

    IsEntered 确定当前线程是否保留指定对象锁。

    Pulse 通知等待队列中的线程锁定对象状态的更改。

    PulseAll 通知所有的等待线程对象状态的更改。

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

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

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

  • 相关阅读:
    js中let和var定义变量的区别
    windows下开发PHP扩展dll(无需Cygwin)
    用VS开发PHP扩展
    破解电信光猫华为HG8120C关闭路由功能方法
    从程序员到项目经理(二十九):怎样写文档
    从程序员到项目经理(二十八):该死的结果导向(只看结果,不问过程到底行不行?)
    从程序员到项目经理(二十七):怎样给领导汇报工作
    从程序员到项目经理(二十六):项目管理不能浑水摸鱼
    从程序员到项目经理(二十五):对绩效考核的吐槽
    从程序员到项目经理(二十四):慎于问敏于行
  • 原文地址:https://www.cnblogs.com/dcz2015/p/5035160.html
Copyright © 2011-2022 走看看