线程基本概念,线程体系讲座

By admin in 4858.com on 2019年4月2日

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//创设线程
//两组范围为壹-十的数字会随机交叉输出,表达PrintNumbers方法同时运营在主线程和另二个线程中
namespace Recipe1
{
class Program
{
static void Main(string[] args)
{
Thread th = new Thread(PrintNumbers);
th.Start();
PrintNumbers();
Console.ReadKey();
}
static void PrintNumbers()
{
Console.WriteLine(“Starting”);
for (int i = 1; i < 10; i++)
{
Console.WriteLine(i);
}
}
}
}

原文:

using System; using System.Threading; class Program { static void
Main(string[] args) { Console.WriteLine(“主线程初始”);
/*=========================================/ Thread
类拥用多少个重载的构造函数,常用的两个接收一个ThreadStart类型的参数 public
Thread ( ThreadStart start) ThreadStart是三个寄托,定义如下 public
delegate void ThreadStart()
/=========================================*/ Thread th = new Thread(new
ThreadStart(ThreadMethod)); //也可简写为new Thread(ThreadMethod);
th.Start(); //运行线程 for (char i = ‘a’; i < ‘k’; i++) {
Console.WriteLine(“主线程:{0}”, i); Thread.Sleep(十0); } th.Join();
//主线程等待支援线程甘休 Console.WriteLine(“主线程截至”);
Console.ReadKey(); } static void ThreadMethod() {
Console.WriteLine(“匡助线程开首…”); for (int i = 0; i < 10; i++) {
Console.WriteLine(“协助线程:{0}”, i); Thread.Sleep(200); }
Console.WriteLine(“帮忙线程甘休.”); } }

**本文为原创,如需转发,请评释小编和出处,多谢!

 

运转结果:

**

引言

主线程初阶
主线程:a
帮忙线程起先…
帮忙线程:0
主线程:b
主线程:c
赞助线程:一
主线程:d
主线程:e
救助线程:二
主线程:f
支持线程:三
主线程:g
主线程:h
支援线程:四
主线程:i
主线程:j
扶持线程:伍
帮扶线程:6
支持线程:柒
匡助线程:捌
接济线程:9
救助线程甘休.
主线程甘休

上一篇:C#线程类别讲座(一):BeginInvoke和EndInvoke方法

  随着双核、四核等多核处理器的放大,多核处理器或超线程单核处理器的电脑已很广阔,基于多核处理的编制程序技术也早先面临程序员们普遍关怀。那之中一个注重的方面就是营造拾2线程应用程序(因为不应用二十四线程的话,开发人士就不可能丰盛发挥多核处理器的有力质量)。

一、            
Thread类的主导用法

  本文针对的是营造基于单核总结机的二十102线程应用程序,意在介绍十二线程相关的基本概念、内涵,以及如何通过System.Threading命名空间的类、委托和BackgroundWorker组件等两种手段营造十2线程应用程序。

透过System.Threading.Thread类能够初步新的线程,并在线程堆栈中运维静态或实例方法。可以经过Thread类的的构造方法传递八个无参数,并且不再次来到值(重回void)的寄托(ThreadStart),那些委托的定义如下:

  本文如果能为刚接触二十多线程的朋友起到投砾引珠的成效也就心潮澎湃了。当然,本人才疏学浅,文中难免会有欠缺或不当的地点,恳请各位朋友多多教导。

[ComVisibleAttribute(true)]

  一.驾驭三十二线程

public delegate void ThreadStart()

  大家一般精通的应用程序正是2个*.exe文件,当运行*.exe应用程序未来,系统会在内部存款和储蓄器中为该程序分配一定的半空中,同时加载一些该程序所需的财富。其实那就能够叫做创立了几个进度,能够经过Windows职务管理器查看这么些过程的相干新闻,如影象名称、用户名、内存使用、PID(唯壹的经过标示)等,如图下所示。

作者们得以因而如下的方法来建立并运维2个线程。

    

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

  而线程则只是经过中的2个主导举办单元。3个应用程序往往唯有1个程序入口,如:

namespace MyThread
{
    class Program
    {
        public static void myStaticThreadMethod()
        {
            Console.WriteLine(“myStaticThreadMethod”);
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(myStaticThreadMethod);
            thread1.Start();  // 只要使用Start方法,线程才会运作
        }
    }
}

  [STAThread]

    除了运转静态的法子,还能在线程中运营实例方法,代码如下:

  static void Main()   //应用程序主入口点

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

  {

namespace MyThread
{
    class Program
    {
        public void myThreadMethod()
        {
            Console.WriteLine(“myThreadMethod”);
        }
        static void Main(string[] args)
        {
            Thread thread2 = new Thread(new Program().myThreadMethod);
            thread2.Start();
        }
    }
}

  Application.EnableVisualStyles();

   
假如读者的艺术极粗略,或出来某种指标,也足以通过匿名委托或Lambda表达式来为Thread的构造方法赋值,代码如下:

  Application.SetCompatibleTextRenderingDefault(false);

Thread thread3 = new Thread(delegate() { Console.WriteLine(“匿名委托”); });
thread3.Start();

  Application.Run(new MainForm());

Thread thread4 = new Thread(( ) => { Console.WriteLine(“Lambda表达式”); });
thread4.Start();

  }

    在那之中Lambda表明式前边的(
)表示并未有参数。

  进程会蕴藏2个跻身此入口的线程,咱们称为主线程。当中,天性
[STAThread]
提示应用程序的暗中同意线程模型是单线程单元(相关音信可参照http://msdn.microsoft.com/en-us/library/system.stathreadattribute(VS.71).aspx.aspx))。只包蕴几个主线程的进程是线程安全的,也正是程序仅有一条工作线,唯有成就了前边的职责才能实施排在前面包车型客车职责。

    为了区别区别的线程,还足以为Thread类的Name属性赋值,代码如下:

  然当在程序处理3个很耗费时间的任务,如输出三个大的文书或远程访问数据库等,此时的窗体界面程序对用户而言基本像是没影响1样,菜单、按钮等都用持续。因为窗体上控件的响应事件也是内需主线程来实施的,而主线程正忙着干任何的事,控件响应事件就只可以排队等着主线程忙完了再进行。

Thread thread5 = new Thread(() => { Console.WriteLine(Thread.CurrentThread.Name); });
thread5.Name = “我的Lamdba”;
thread5.Start();

  为了制服单线程的这么些毛病,Win3二API能够让主线程再创设别的的次线程,但无论是是主线程依旧次线程都是进程中单独的施行单元,能够同时访问共享的多少,这样就有了二十八线程这一个定义。

    假设将地方thread一至thread5松开1起实施,由于系统对线程的调度区别,输出的结果是不定的,如图一是一种大概的出口结果。

  相信到那,应该对10二线程有个相比感性的认识了。但作者在那要提示一下,基于单核总括机的二十多线程其实只是操作系统施展的五个障眼法而已(但那不会纷扰大家领悟创设八线程应用程序的思绪),他并无法收缩完毕有着职分的小时,有时反而还会因为使用过多的线程而降落质量、延长期。之所以这么,是因为对于单CPU而言,在八个单位时间(也称时间片)内,只可以执行二个线程,即只可以干一件事。当1个线程的时光片用完时,系统会将该线程挂起,下多个日子内再进行另一个线程,如此,CPU以时间片为距离在多个线程之间交替执行运算(其实那里还与每一种线程的优先级有关,级别高的会预先处理)。由于交替时间间隔非常短,所以造成了各种线程都在“同时”工作的假象;而1旦线程数目过多,由于系统挂起线程时要记录线程当前的景观数据等,那样又势必会下降程序的一体化品质。但对于那个,多核处理器就能从本质上(真正的还要工作)提升程序的履行作用。

4858.com 1

  2. 线程异步与线程同步

                                                                 图1

  从线程执行职分的措施上可以分成线程同步和线程异步。而为了方便清楚,后边描述中用“同步线程”指代与线程同步相关的线程,同样,用“异步线程”表示与线程异步相关的线程。

二、
定义四个线程类

  线程异步就是消除类似前面提到的实践耗费时间职务时界面控件不能够使用的难题。如创设一个次线程去专门实施耗时的职分,而别的如界面控件响应那样的职责交给另1个线程执行(往往由主线程执行)。这样,七个线程之间通过线程调度器长期(时间片)内的切换,就模拟出四个任务“同时”被实践的功能。

    大家得以将Thread类封装在1个MyThread类中,以使任何从MyThread继承的类都装有八线程能力。MyThread类的代码如下:

  线程异步往往是透过创造多少个线程执行五个职务,两个工作线同时开工,类似多辆在周围的公路上互相的汽车还要发展,互不困扰(读者要明了,本质上并从未“同时”,仅仅是操作系统玩的1个障眼法。但那一个障眼法却对拉长我们的主次与用户之间的相互、以及压实程序的友好性很有用,不是吧)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace MyThread
{
   abstract class MyThread
    {
       Thread thread = null;

  在介绍线程同步在此之前,先介绍一个与此紧凑有关的概念——并发难题。

       abstract public void run();    

  前面提到,线程都是独自的履行单元,能够访问共享的数额。也正是说,在三个享有七个次线程的程序中,每种线程都足以访问同1个共享的数据。再稍加思索你会发现那样也许会出标题:由于线程调度器会随便的挂起某2个线程(前边介绍的线程间的切换),所以当线程a对共享数据D的造访(修改、删除等操作)完结以前被挂起,而此时线程b又刚好去做客数据D,那么线程b访问的则是二个不安宁的数据。那样就会发出13分难以发现bug,由于是不管37二十一产生的,发生的结果是不可预测的,这样样的bug也都很难重现和调节和测试。那就是出新难点。

        public void start()
        {
            if (thread == null)
                thread = new Thread(run);
            thread.Start();
        }
    }
线程基本概念,线程体系讲座。}

  为了消除八线程共同访问贰个共享能源(也称互斥访问)时发出的出现难点,线程同步就涌出了。线程同步的机理,简而言之,便是幸免多少个线程同时做客有些共享的能源。做法非常粗略,标记访问某共享能源的那有个别代码,当程序运维到有记号的地点时,CL中华V(具体是怎么能够先不管,只要驾驭它能操纵就行)对各线程举行调整:借使已有线程在拜访一财富,CL逍客就会将其余访问这一能源的线程挂起,直到前一线程截止对该能源的造访。那样就保证了同临时间唯有三个线程访问该能源。打个比方,就像是某财富放在只有1独古桥相连的半壁江山上,若是要运用该能源,大家就得排队,一个一个来,前边的回到了,下1个再去,前边的没回来,前面包车型客车就原地待命。

   
能够用上面包车型大巴代码来使用MyThread类。

  那里只是把中央的定义及原理做了1个大致的阐释,不至于看后面包车型地铁次第时糊里凌乱的。具体怎么编写代码,下边包车型大巴段落将做详细介绍。

class NewThread : MyThread
{
      override public void run()
      {
          Console.WriteLine(“使用MyThread建立并运营线程”);
      }
  }

 

  static void Main(string[] args)
  {

 

      NewThread nt = new NewThread();
      nt.start();
  }

  3.成立八线程应用程序

     大家还足以应用MyThread来为线程传递任意复杂的参数。详细内容见下节。

  那里做一个简单易行的认证:上边首要通过介绍通过System.Threading命名空间的类、委托和BackgroundWorker组件二种不相同的手段创设三十二线程应用程序,具体会从线程异步和线程同步多少个方面来阐释。

三、    
为线程传递参数

  叁.壹经过System.Threading命名空间的类营造

Thread类有四个带参数的委托项目标重载方式。那个委托的定义如下:

  在.NET平台下,System.Threading命名空间提供了许多类型来创设八线程应用程序,可以说是专为八线程服务的。由于本文仅是回想到3个“一得之见”的功用,所以对于那壹块不会追究过多、过深,重要采取System.Threading.Thread类。

[ComVisibleAttribute(false)]

  先从System.Threading.Thread类自己有关的一个小例子说到,代码如下,解释见注释:

public delegate void ParameterizedThreadStart(Object obj)

  using System;

4858.com,以此Thread类的构造方法的概念如下:

  using System.Threading; //引入System.Threading命名空间

 

  namespace MultiThread

public Thread(ParameterizedThreadStart start);

  {

下边包车型地铁代码应用了这些带参数的委托向线程传递一个字符串参数:

  class Class

public static void myStaticParamThreadMethod(Object obj)
{
    Console.WriteLine(obj);
}

  {

static void Main(string[] args)
{
      Thread thread = new Thread(myStaticParamThreadMethod);
      thread.Start(“通过信托的参数字传送值”);
}

  static void Main(string[] args)

要留心的是,如若使用的是不带参数的嘱托,不可能利用带参数的Start方法运维线程,不然系统会抛出特别。但运用带参数的寄托,能够选择thread.Start()来运营线程,那时所传递的参数值为null。

  {

    也足以定义3个类来传递参数值,如下边包车型客车代码如下:

  Console.WriteLine(“**************
显示当前线程的相干新闻 *************”);

class MyData
{
    private String d1;
    private int d2;
    public MyData(String d1, int d2)
    {
          this.d1 = d1;
          this.d2 = d2;
    }
    public void threadMethod()
    {
          Console.WriteLine(d1);
          Console.WriteLine(d2);
    }
}

  //评释线程变量并赋值为当前线程

MyData myData = new MyData(“abcd”,1234);
Thread thread = new Thread(myData.threadMethod);
thread.Start();

  Thread primaryThread = Thread.CurrentThread;

   
要是选择在其次节定义的MyThread类,传递参数会来得更简单,代码如下:

  //赋值线程的称号

class NewThread : MyThread
{
    private String p1;
    private int p2;
    public NewThread(String p1, int p2)
    {
        this.p1 = p1;
        this.p2 = p2;
    }

  primaryThread.Name = “主线程”;

    override public void run()
    {
        Console.WriteLine(p1);
        Console.WriteLine(p2);
    }
}

  //显示线程的有关新闻

NewThread newThread = new NewThread(“hello world”, 4321);
newThread.start();

  Console.WriteLine(“线程的名字:{0}”, primaryThread.Name);

肆、    
前台和后台线程

  Console.WriteLine(“线程是不是运转? {0}”, primaryThread.IsAlive);

    使用Thread建立的线程暗许境况下是前台线程,在经过中,只要有3个前台线程未脱离,进度就不会终止。主线程正是八个前台线程。而后台线程不管线程是不是结束,只要持有的前台线程都退出(包含常规退出和丰富退出)后,进度就会自行终止。1般后台线程用于拍卖时间较短的天职,如在3个Web服务器中得以选择后台线程来处理客户端发过来的央求消息。而前台线程一般用于拍卖要求长日子等待的天职,如在Web服务器中的监听客户端请求的顺序,或是定时对少数系统财富进行围观的先后。下边包车型地铁代码演示了前台和后台线程的分别。

  Console.WriteLine(“线程的预先级: {0}”, primaryThread.Priority);

public static void myStaticThreadMethod()
{
    Thread.Sleep(3000);
}

  Console.WriteLine(“线程的情形: {0}”, primaryThread.ThreadState);

Thread thread = new Thread(myStaticThreadMethod);
// thread.IsBackground = true;
thread.Start();

  Console.ReadLine();

    倘使运行方面包车型大巴代码,程序会等待3秒后脱离,若是将注释去掉,将thread设成后台线程,则程序会即时退出。

  }

    要小心的是,必须在调用Start方法以前安装线程的档次,不然1但线程运转,将不能更改其种类。

  }

    通过BeginXXX方法运转的线程都现在台线程

  }

伍、  
判断多少个线程是不是都终止的二种艺术

  输出结果如下:

规定全体线程是或不是都成功了劳作的主意有成都百货上千,如能够动用类似于对象计数器的法门,所谓指标计数器,便是2个目的被引用一遍,那么些计数器就加1,销毁引用就减一,假设引用数为0,则垃圾搜集器就会对这几个引用数为0的目的进行回收。

  ************** 展现当前线程的有关音讯
*************

艺术1:线程计数器

  线程的名字:主线程

线程也得以应用计数器的办法,即为全数须求监视的线程设贰个线程计数器,每起头3个线程,在线程的举办措施中为这一个计数器加一,如若有些线程截止(在线程执行情势的最后为那些计数器减一),为这些计数器减1。然后再起来叁个线程,按着一定的年月间隔来监视那么些计数器,如是棕个计数器为0,表明全部的线程都截至了。当然,也得以毫无这些监视线程,而在每3个办事线程的尾声(在为计数器减1的代码的末尾)来监视这几个计数器,也就是说,每三个工作线程在退出以前,还要负担检验这一个计数器。使用那种措施毫无忘了1道那么些计数器变量啊,不然会生出意想不到的后果。

  线程是还是不是运转? True

方法二:使用Thread.join方法

  线程的预先级: Normal

join方法唯有在线程停止时才继续执行下边包车型地铁话语。可以对每贰个线程调用它的join方法,但要注意,那几个调用要在另贰个线程里,而毫无在主线程,不然程序会被卡住的。

  线程的动静: Running

    个人感觉那种艺术比较好。

  对于位置的代码不想做过多解释,只说一下Thread.CurrentThread获得的是实践当前代码的线程。

   
**线程计数器方法言传身教:

  三.一.一异步调用线程

**

  那里先说一下前台线程与后台线程。前台线程能阻碍应用程序的停下,既直到全体前台线程终止后才会干净关闭应用程序。而对后台线程而言,当全体前台线程终止时,后台线程会被活动截止,不论后台线程是或不是正在履行职务。默许情形下通过Thread.Start()方法创造的线程都自动为前台线程,把线程的习性IsBackground设为true时就将线程转为后台线程。

    class ThreadCounter : MyThread
    {
        private static int count = 0;
        private int ms;
        private static void increment()
        {
            lock (typeof(ThreadCounter))  // 必须共同计数器
            {
                count++;
            }
        }
        private static void decrease()
        {
            lock (typeof(ThreadCounter))
            {
                count–;
            }
        }
        private static int getCount()
        {
            lock (typeof(ThreadCounter))
            {
                return count;
            }
        }
        public ThreadCounter(int ms)
        {
            this.ms = ms;
        }
        override public void run()
        {
            increment();
            Thread.Sleep(ms);
            Console.WriteLine(ms.ToString()+”纳秒职分完成”);
            decrease();
            if (getCount() == 0)
                Console.WriteLine(“全体任务完成”);
        }
    }

  上边先看叁个例证,该例子创立三个次线程执行打字与印刷数字的职务,而主线程则干任何的事,两者同时拓展,互不苦恼。

ThreadCounter counter1 = new ThreadCounter(3000);
ThreadCounter counter2 = new ThreadCounter(5000);
ThreadCounter counter3 = new ThreadCounter(7000);

  using System;

counter1.start();
counter2.start();
counter3.start();

  using System.Threading;

   
上边的代码即使在大部的时候能够符合规律干活,但却存在八个隐患,正是一旦某些线程,尽管是counter1,在运作后,由于有些原因,其余的线程并未有运行,在那种情况下,在counter一运营完后,如故能够显得出“全体职分完毕”的提示音讯,不过counter2和counter三还从未运营。为了排除这一个隐患,可以将increment方法从run中移除,将其置于ThreadCounter的构造方法中,在此刻,increment方法中的lock也足以去掉了。代码如:
        public ThreadCounter(int ms)
        {
            this.ms = ms;
            increment();
        }

  using System.Windows.Forms;

    运营方面的主次后,将呈现如图二的结果。

  namespace MultiThread

4858.com 2

  {

                                                                 图2

  class Class

动用Thread.join方法言传身教

  {

private static void threadMethod(Object obj)
{
    Thread.Sleep(Int32.Parse(obj.ToString()));
    Console.WriteLine(obj + “皮秒职务完结”);
}
private static void joinAllThread(object obj)
{
    Thread[] threads = obj as Thread[];
    foreach (Thread t in threads)
        t.Join();
    Console.WriteLine(“全体的线程甘休”);
}

  static void Main(string[] args)

static void Main(string[] args)
{
    Thread thread1 = new Thread(threadMethod);
    Thread thread2 = new Thread(threadMethod);
    Thread thread3 = new Thread(threadMethod);

  {

     thread1.Start(3000);
     thread2.Start(5000);
     thread3.Start(7000);

  Console.WriteLine(“************* 多个线程同时工作
*****************”);

     Thread joinThread = new Thread(joinAllThread);
     joinThread.Start(new Thread[] { thread1, thread2, thread3 });

  //主线程,因为得到的是时下在进行Main()的线程

}

  Thread primaryThread = Thread.CurrentThread;

    在运营方面包车型大巴代码后,将会获取和图二同样的运转结果。上述二种艺术都尚未线程数的范围,当然,仍旧会受到操作系统和硬件能源的限制。**

  primaryThread.Name = “主线程”;

下一篇:**C#线程类别讲座(三):线程池和文书下载服务器

  Console.WriteLine(“-> {0} 在履行主函数 Main()。”,
Thread.CurrentThread.Name);

  //次线程,该线程指向PrintNumbers()方法

  Thread SecondThread = new Thread(new ThreadStart(PrintNumbers));

  SecondThread.Name = “次线程”;

  //次线程最西子行针对的不二等秘书籍

  SecondThread.Start();

  //同时主线程在实施主函数中的其余职分

  MessageBox.Show(“正在推行主函数中的职责。。。。”,
“主线程在工作…”);

  Console.ReadLine();

  }

  //打印数字的章程

  static void PrintNumbers()

  {

  Console.WriteLine(“-> {0} 在推行打字与印刷数字函数 PrintNumber()”,
Thread.CurrentThread.Name);

  Console.WriteLine(“打字与印刷数字: “);

  for (int i = 0; i < 10; i++)

  {

  Console.Write(“{0}, “, i);

  //Sleep()方法使当前线程挂等待钦命的时间长度在推行,那里关键是模仿打字与印刷职分

  Thread.Sleep(2000);

  }

  Console.WriteLine();

  }

  }

  }

  程序运营后会看到贰个窗口弹出,如图所示,同时决定台窗口也在不断的来得数字。

    4858.com 3

  输出结果为:

  ************* 五个线程同时工作
*****************

  -> 主线程 在进行主函数 Main()。

  -> 次线程 在执行打字与印刷数字函数 PrintNumber()

  打印数字:

  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

 

上一页  [1] [2] [3] [4] [5] [6] 下一页

欢迎进入.NET社区论坛,与200万技术人士互动交流>>进入

 

  那里稍微对 Thread SecondThread = new Thread(new
ThreadStart(PrintNumbers)); 这一句做个表明。其实 ThreadStart 是
System.Threading 命名空间下的1个委托,其声称是 public delegate void
ThreadStart(),指向不带参数、重临值为空的法子。所以当使用 ThreadStart
时,对应的线程就不得不调用不带参数、重回值为空的点子。这非要指向含参数的主意呢?在System.Threading命名空间下还有2个ParameterizedThreadStart 委托,其证明是
public delegate void ParameterizedThreadStart(object obj),能够针对含
object 类型参数的章程,那里并非忘了 object
可是具有类别的父类哦,有了它就能够透过创造种种自定义类型,如组织、类等传递很多参数了,那里就不再举例表达了。

  三.一.二并发难点

  那里再经过二个例子让我们具体体会一下前方谈到的面世难题,然后再介绍线程同步。

  using System;

  using System.Threading;

  namespace MultiThread1

  {

  class Class

  {

  static void Main(string[] args)

  {

  Console.WriteLine(“********* 并发难点演示
***************”);

  //创立一个打字与印刷对象实例

  Printer printer = new Printer();

  //声美素佳儿含多少个线程对象的数组

  Thread[] threads = new Thread[10];

  for (int i = 0; i < 10; i++)

  {

  //将每3个线程都针对printer的PrintNumbers()方法

  threads[i] = new Thread(new ThreadStart(printer.PrintNumbers));

  //给各个线程编号

  threads[i].Name = i.ToString() +”号线程”;

  }

  //早先推行全部线程

  foreach (Thread t in threads)

  t.Start();

  Console.ReadLine();

  }

  }

  //打印类

  public class Printer

  {

  //打字与印刷数字的主意

  public void PrintNumbers()

  {

  Console.WriteLine(“-> {0} 正在实施打字与印刷职分,开端打字与印刷数字:”,
Thread.CurrentThread.Name);

  for (int i = 0; i < 10; i++)

  {

  Random r = new Random();

  //为了增添抵触的概率及,使各线程各自等待随机的时间长度

  Thread.Sleep(2000 * r.Next(5));

  //打字与印刷数字

  Console.Write(“{0} “, i);

  }

  Console.WriteLine();

  }

  }

  }

  上边的例子中,主线程爆发的10个线程同时做客同二个目的实例printer的不2诀窍PrintNumbers(),由于未有锁定共享财富(注意,这里是指控制台),所以在PrintNumbers()输出到控制台在此之前,调用PrintNumbers()的线程很或然被挂起,但不领会怎么着时候(或是不是有)挂起,导致获得不可预测的结果。如下是多个例外的结果(当然,读者的运作结果或许会是任何情况)。

    4858.com 4

  情形一

    4858.com 5

  情形二

 

 

 

  三.一.3线程同步

  线程同步的拜访格局也号称阻塞调用,即未有实施完任务不回去,线程被挂起。能够使用C#中的lock关键字,在此关键字范围类的代码都将是线程安全的。lock关键字需定义一个标志,线程进入锁定范围是必须取得那些标记。当锁定的是三个实例级对象的个体方法时行使格局自个儿所在对象的引用就足以了,将方面例子中的打字与印刷类Printer稍做变更,添加lock关键字,代码如下:

  //打印类

  public class Printer

  {

  public void PrintNumbers()

  {

  //使用lock关键字,锁定d的代码是线程安全的

  lock (this)

  {

  Console.WriteLine(“-> {0} 正在实践打字与印刷任务,开首打字与印刷数字:”,
Thread.CurrentThread.Name);

  for (int i = 0; i < 10; i++)

  {

  Random r = new Random();

  //为了扩充冲突的概率及,使各线程各自等待随机的时间长度

  Thread.Sleep(2000 * r.Next(5));

  //打字与印刷数字

  Console.Write(“{0} “, i);

  }

  Console.WriteLine();

  }

  }

  }

  }

  同步后执行结果如下:

    4858.com 6

  也足以接纳System.Threading命名空间下的Monitor类进行共同,两者内涵是相同的,但Monitor类更灵敏,那里就不在做过多的探索,代码如下:

  //打印类

  public class Printer

  {

  public void PrintNumbers()

  {

  Monitor.Enter(this);

  try

  {

  Console.WriteLine(“-> {0} 正在实践打字与印刷义务,开头打字与印刷数字:”,
Thread.CurrentThread.Name);

  for (int i = 0; i < 10; i++)

  {

  Random r = new Random();

  //为了增添龃龉的可能率及,使各线程各自等待随机的时间长度

  Thread.Sleep(2000 * r.Next(5));

  //打字与印刷数字

  Console.Write(“{0} “, i);

  }

  Console.WriteLine();

  }

  finally

  {

  Monitor.Exit(this);

  }

  }

  }

  输出结果与地方的同1。

  三.2由此委托构建多线程应用程序

  在看上面包车型客车剧情时讲求对信托有必然的明白,倘使不领悟的话推荐参考一下新浪张子阳的《C# 中的委托和事件》,里面对信托与事件进展由浅入深的较系统的执教: http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/903360.html。

  那里先举1个关于信托的简练例子,具体表明见注释:

  using System;

  namespace MultiThread

  {

  //定义二个针对性包含三个int型参数、重返值为int型的函数的嘱托

  public delegate int AddOp(int x, int y);

  class Program

  {

  static void Main(string[] args)

  {

  //成立一个指向Add()方法的AddOp对象p

  AddOp pAddOp = new AddOp(Add);

  //使用委托直接调用方法Add()

  Console.WriteLine(“10 + 25 = {0}”, pAddOp(10, 5));

  Console.ReadLine();

  }

  //求和的函数

  static int Add(int x, int y)

  {

  int sum = x + y;

  return sum;

  }

  }

  }

  运营结果为:

  10 + 25 = 15

 

 

 

  三.贰.一线程异步

  先表明一(Wissu)下,那里不打算讲解委托线程异步或共同的参数传递、获取再次回到值等,只是做个1般的始发而已,倘诺前边有时光了再别的写一篇关于四线程中参数字传送递、获取再次回到值的文章。

  注意观看地点的事例会发觉,直接行使委托实例 pAddOp(拾, 五)
就调用了求和方式Add()。很鲜明,那几个主意是由主线程执行的。不过,委托项目中还有其余四个章程——BeginInvoke()和EndInvoke(),上面通超过实际际的事例来表明,将方面的例子做适合改动,如下:

  using System;

  using System.Threading;

  using System.Runtime.Remoting.Messaging;

  namespace MultiThread

  {

  //注脚指向含四个int型参数、重临值为int型的函数的嘱托

  public delegate int AddOp(int x, int y);

  class Program

  {

  static void Main(string[] args)

  {

  Console.WriteLine(“******* 委托异步线程 八个线程“同时”工作
*********”);

  //突显主线程的绝无仅有标示

  Console.WriteLine(“调用Main()的主线程的线程ID是:{0}.”,
Thread.CurrentThread.ManagedThreadId);

  //将委托实例指向Add()方法

  AddOp pAddOp = new AddOp(Add);

  //开端委托次线程调用。委托BeginInvoke()方法重回的档次是IAsyncResult,

  //包罗那委托指向方法结束重返的值,同时也是EndInvoke()方法参数

  IAsyncResult iftAR = pAddOp.BeginInvoke(10, 10, null, null);

  Console.WriteLine(“”nMain()方法中施行别的义务……..”n”);

  int sum = pAddOp.EndInvoke(iftAR);

  Console.WriteLine(“10 + 10 = {0}.”, sum);

  Console.ReadLine();

  }

  //求和章程

  static int Add(int x, int y)

  {

  //提示调用该措施的线程ID,ManagedThreadId是线程的绝无仅有标示

  Console.WriteLine(“调用求和办法 Add()的线程ID是: {0}.”,
Thread.CurrentThread.ManagedThreadId);

  //模拟2个进度,停留5秒

  Thread.Sleep(5000);

  int sum = x + y;

  return sum;

  }

  }

  }

  运营结果如下:

  ******* 委托异步线程 七个线程“同时”工作 *********

  调用Main()的主线程的线程ID是:10.

  Main()方法中执行其它职责……..

  调用求和办法 Add()的线程ID是: 7.

  10 + 10 = 20.

  叁.二.2线程同步

  委托中的线程同步首要涉嫌到上边使用的pAddOp.BeginInvoke(10, 拾, null,
null)方法中前面多个为null的参数,具体的能够参照相关资料。那里代码如下,解释见代码注释:

  using System;

  using System.Threading;

  using System.Runtime.Remoting.Messaging;

  namespace MultiThread

  {

  //评释指向含五个int型参数、重返值为int型的函数的嘱托

  public delegate int AddOp(int x, int y);

  class Program

  {

  static void Main(string[] args)

  {

  Console.WriteLine(“******* 线程同步,“阻塞”调用,八个线程工作
*********”);

  Console.WriteLine(“Main() invokee on thread {0}.”,
Thread.CurrentThread.ManagedThreadId);

  //将委托实例指向Add()方法

  AddOp pAddOp = new AddOp(Add);

  IAsyncResult iftAR = pAddOp.BeginInvoke(10, 10, null, null);

  //判断委托线程是还是不是推行完职责,

  //未有到位的话,主线程就做任何的事

  while (!iftAR.IsCompleted)

  {

  Console.WriteLine(“Main()方法工作中…….”);

  Thread.Sleep(1000);

  }

  //得到重回值

  int answer = pAddOp.EndInvoke(iftAR);

  Console.WriteLine(“10 + 10 = {0}.”, answer);

  Console.ReadLine();

  }

  //求和章程

  static int Add(int x, int y)

  {

  //提醒调用该方法的线程ID,ManagedThreadId是线程的唯一标示

  Console.WriteLine(“调用求和办法 Add()的线程ID是: {0}.”,
Thread.CurrentThread.ManagedThreadId);

  //模拟2个历程,停留5秒

  Thread.Sleep(5000);

  int sum = x + y;

  return sum;

  }

  }

  }

 

 

  运维结果如下:

  ******* 线程同步,“阻塞”调用,多个线程工作 *********

  Main() invokee on thread 10.

  Main()方法工作中…….

  调用求和办法 Add()的线程ID是: 七.

  Main()方法工作中…….

  Main()方法工作中…….

  Main()方法工作中…….

  Main()方法工作中…….

  10 + 10 = 20.

  3.3BackgroundWorker组件

  BackgroundWorker组件位于工具箱中,用于方便的成立线程异步的次第。新建2个WindowsForms应用程序,界面如下:

    4858.com 7

  代码如下,解释参见注释:

  private void button1_Click(object sender, EventArgs e)

  {

  try

  {

  //获得输入的数字

  int numOne = int.Parse(this.textBox1.Text);

  int numTwo = int.Parse(this.textBox2.Text);

  //实例化参数类

  AddParams args = new AddParams(numOne, numTwo);

  //调用RunWorkerAsync()生成后台线程,同时传入参数

  this.backgroundWorker1.RunWorkerAsync(args);

  }

  catch (Exception ex)

  {

  MessageBox.Show(ex.Message);

  }

  }

  //backgroundWorker新生成的线程开头工作

  private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)

  {

  //获取传入的AddParams对象

  AddParams args = (AddParams)e.Argument;

  //停留五秒,模拟耗时任务

  Thread.Sleep(5000);

  //返回值

  e.Result = args.a + args.b;

  }

  //当backgroundWorker一的DoWork中的代码执行完后会触发该事件

  //同时,其实施的结果会含有在RunWorkerCompleted伊夫ntArgs参数中

  private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)

  {

  //展现运算结果

  Message博克斯.Show(“运营结果为:” + e.Result.ToString(), “结果”);

  }

  }

  //参数类,那么些类仅仅起到三个笔录并传递参数的功能

  class AddParams

  {

  public int a, b;

  public AddParams(int numb1, int numb2)

  {

  a = numb1;

  b = numb2;

  }

  }

  注意,在测算结果的还要,窗体能够任意活动,也能够重复在文本框中输入音讯,那就证实主线程与backgroundWorker组件生成的线程是异步的。

  4.总结

  本文从线程、进程、应用程序的关联开端,介绍了1部分关于八线程的基本概念,同时阐述了线程异步、线程同步及出现难点等。最终从使用角度出发,介绍了怎么通过System.Threading命名空间的类、委托和BackgroundWorker组件等三种手段营造八线程应用程序。

发表评论

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

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有