线程基本概念,二十八线程编制程序实战一

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//创立线程
//两组范围为1-拾的数字会随机交叉输出,表达PrintNumbers方法同时运行在主线程和另3个线程中
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
类拥用6个重载的构造函数,常用的2个收到四个ThreadStart类型的参数 public
Thread ( ThreadStart start) ThreadStart是1个委托,定义如下 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
帮衬线程:3
主线程:g
主线程:h
补助线程:4
主线程:i
主线程:j
支援线程:伍
扶持线程:陆
帮扶线程:七
扶助线程:八
协理线程:九
赞助线程结束.
主线程截止

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

  随着双核、四核等多核处理器的拓宽,多核处理器或超线程单核处理器的Computer已很广阔,基于多核处理的编制程序手艺也开始遭逢程序员们广泛关怀。那里面二个至关心重视要的上边就是营造八线程应用程序(因为不选用多线程的话,开辟人士就无法丰硕发挥多核处理器的庞大品质)。

壹、            
Thread类的中坚用法

  本文针对的是营造基于单核Computer的拾二线程应用程序,目的在于介绍三十二线程相关的基本概念、内涵,以及怎么样通过System.Threading命名空间的类、委托和BackgroundWorker组件等三种花招塑造八线程应用程序。

经过System.Threading.Thread类能够起来新的线程,并在线程货仓中运转静态或实例方法。可以由此Thread类的的构造方法传递2个无参数,并且不重回值(再次回到void)的委托(ThreadStart),这几个委托的概念如下:

  本文假设能为刚接触八线程的朋友起到引玉之砖的功效也就满面春风了。当然,本人才疏学浅,文中难免会有欠缺或错误的位置,恳请各位朋友多多引导。

[ComVisibleAttribute(true)]

  一.领悟拾二线程

public delegate void ThreadStart()

  大家平常精晓的应用程序便是三个*.exe文件,当运行*.exe应用程序以往,系统会在内部存款和储蓄器中为该程序分配一定的上空,同时加载一些该程序所需的能源。其实那就能够称之为创设了一个进度,能够经过Windows职务管理器查看这些进程的连锁音讯,如印象名称、用户名、内部存款和储蓄器使用、PID(唯1的进度标示)等,如图下所示。

小编们可以因此如下的章程来树立并运维三个线程。

    

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

  而线程则只是经过中的三个为主进行单元。3个应用程序往往唯有一个程序入口,如:

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表达式前边的(
)表示从没参数。

  进度会蕴藏二个进去此入口的线程,我们誉为主线程。其中,特性
[STAThread]
提示应用程序的暗中认可线程模型是单线程单元(相关信息可参照http://msdn.microsoft.com/en-us/library/system.stathreadattribute(VS.71).aspx.aspx))。只含有1个主线程的历程是线程安全的,相当于程序仅有一条职业线,唯有成功了前头的职务技艺施行排在前面包车型大巴职责。

    为了分裂差别的线程,还是可感到Thread类的Name属性赋值,代码如下:

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

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

  为了制服单线程的那一个毛病,Win32API能够让主线程再次创下制其余的次线程,但无论是主线程依然次线程都以进度中单独的实行单元,能够同时访问共享的多寡,那样就有了八线程那一个定义。

    假诺将地方thread壹至thread5放手一同施行,由于系统对线程的调度差别,输出的结果是不定的,如图一是1种可能的出口结果。

  相信到那,应该对10二线程有个相比感性的认识了。但小编在那要提醒一下,基于单核Computer的多线程其实只是操作系统施展的3个障眼法而已(但那不会干扰我们清楚营造二十四线程应用程序的思路),他并不可能减弱实现具有职分的时间,有时反而还会因为运用过多的线程而下落品质、延长期。之所以那样,是因为对此单CPU而言,在五个单位时间(也称时间片)内,只可以进行二个线程,即只好干1件事。当贰个线程的年华片用完时,系统会将该线程挂起,下一个时光内再进行另3个线程,如此,CPU以时间片为距离在三个线程之间轮换试行运算(其实那里还与各种线程的优先级有关,等级高的会优先处理)。由于交替时间间隔非常短,所以导致了逐1线程都在“同时”职业的假象;而只要线程数目过多,由于系统挂起线程时要记录线程当前的情事数据等,那样又势必会降低程序的全体品质。但对于这个,多核处理器就能从实质上(真正的还要工作)进步程序的实践功用。

亚洲必赢官网 1

  二. 线程异步与线程同步

                                                                 图1

  从线程施行职责的措施上得以分为线程同步和线程异步。而为了便于理解,后边描述中用“同步线程”指代与线程同步相关的线程,同样,用“异步线程”表示与线程异步相关的线程。

贰、
定义叁个线程类

  线程异步就是焚林而猎类似前边提到的实施耗费时间任务时分界面控件不能利用的标题。如创制3个次线程去专门试行耗费时间的职务,而别的如分界面控件响应那样的天职交给另一个线程施行(往往由主线程试行)。那样,五个线程之间通过线程调度器长期(时间片)内的切换,就模拟出三个职分“同时”被施行的坚守。

    大家得以将Thread类封装在3个MyThread类中,以使任何从MyThread承袭的类都具备多线程手艺。MyThread类的代码如下:

  线程异步往往是因此创办多个线程施行几个职分,多少个职业线同时开工,类似多辆在广大的公路上互动的小车还要发展,互不干扰(读者要精通,本质上并未“同时”,仅仅是操作系统玩的三个障眼法。但那么些障眼法却对增高大家的顺序与用户之间的互动、以及抓实程序的友好性很有用,不是啊)。

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

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

       abstract public void run();    

  前面提到,线程都以独自的实施单元,能够访问共享的数量。也正是说,在一个全部四个次线程的先后中,各种线程都得以访问同二个共享的数码。再稍加思考你会发觉那样只怕会出难点:由于线程调度器会自由的挂起某叁个线程(前面介绍的线程间的切换),所以当线程a对共享数据D的造访(修改、删除等操作)实现从前被挂起,而此时线程b又凑巧去拜谒数据D,那么线程b访问的则是二个不稳固的数额。那样就会发出10分难以发现bug,由于是任意产生的,产生的结果是不行预测的,那样样的bug也都很难重现和调节和测试。那正是出新难题。

        public void start()
        {
            if (thread == null)
                thread = new Thread(run);
            thread.Start();
        }
    }
}

  为了消除二十多线程共同访问3个共享财富(也称互斥访问)时产生的产出难点,线程同步就应运而生了。线程同步的机理,一句话来说,就是防守四个线程同时做客有个别共享的能源。做法很简短,标识访问某共享财富的那有个别代码,当程序运营到有标记的地方时,CL奥迪Q3(具体是何等可以先不管,只要通晓它能说了算就行)对各线程举行调控:假诺已有线程在拜访壹能源,CL途达就会将其余访问那1资源的线程挂起,直到前一线程截止对该能源的造访。那样就有限协理了同一时半刻间只有一个线程访问该能源。打个比方,就像某财富放在唯有壹独木桥相连的半壁江山上,若是要利用该能源,大家就得排队,三个二个来,前边的回到了,下1个再去,前边的没回来,前边的就原地待命。

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

  那里只是把大旨的定义及原理做了3个大致的演讲,不至于看后边的次序时糊里凌乱的。具体哪些编写代码,上面包车型地铁段子将做详细介绍。

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

 

  static void Main(string[] args)
  {

 

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

  三.成立十二线程应用程序

     我们还能运用MyThread来为线程传递任意复杂的参数。详细内容见下节。

  这里做一个简便的验证:下边主要通过介绍通过System.Threading命名空间的类、委托和BackgroundWorker组件二种区别的手腕创设拾贰线程应用程序,具体会从线程异步和线程同步五个地点来演讲。

三、    
为线程传递参数

  三.1透过System.Threading命名空间的类构建

Thread类有贰个带参数的嘱托项指标重载形式。那么些委托的定义如下:

  在.NET平台下,System.Threading命名空间提供了不少类型来创设二十四线程应用程序,能够说是专为多线程服务的。由于本文仅是想起到多少个“引玉之砖”的意义,所以对于那1块不会追究过多、过深,主要利用System.Threading.Thread类。

[ComVisibleAttribute(false)]

  先从System.Threading.Thread类本人有关的2个小例子谈到,代码如下,解释见注释:

public delegate void ParameterizedThreadStart(Object obj)

  using System;

以此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。

  {

    也得以定义三个类来传递参数值,如上面包车型客车代码如下:

  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;

   
借使使用在第3节定义的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建立的线程暗中同意意况下是前台线程,在进程中,只要有三个前台线程未脱离,进程就不会终止。主线程正是1个前台线程。而后台线程不管线程是或不是终止,只要抱有的前台线程都退出(包罗健康退出和十分退出)后,进程就会自动终止。一般后台线程用于拍卖时间较短的天职,如在一个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方法在此以前安装线程的花色,不然壹但线程运转,将不可能更动其品种。

  }

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

  }

5、  
判别多少个线程是或不是都得了的三种艺术

  输出结果如下:

明确全部线程是不是都实现了工作的格局有诸多,如能够动用类似于对象计数器的法子,所谓指标计数器,正是三个目的被引用3遍,那几个计数器就加1,销毁引用就减1,假如引用数为0,则垃圾搜聚器就会对这个引用数为0的对象举办回收。

  ************** 展现当前线程的相干消息
*************

情势一:线程计数器

  线程的名字:主线程

线程也能够应用计数器的艺术,即为全体必要监视的线程设三个线程计数器,每先河贰个线程,在线程的施行形式中为这些计数器加壹,借使某些线程结束(在线程试行措施的最终为那个计数器减1),为那一个计数器减一。然后再初步一个线程,按着一定的日子间隔来监视这么些计数器,如是棕个计数器为0,表明具有的线程都终止了。当然,也足以不用那几个监视界程,而在每四个做事线程的结尾(在为计数器减一的代码的背后)来监视这些计数器,也正是说,每三个办事线程在剥离从前,还要承担检查评定这些计数器。使用这种格局毫无忘了伙同那几个计数器变量啊,不然会发生意想不到的结局。

  线程是不是运维? True

方法二:使用Thread.join方法

  线程的先行级: Normal

join方法唯有在线程甘休时才继续推行上边包车型大巴说话。能够对每1个线程调用它的join方法,但要注意,那么些调用要在另多少个线程里,而毫无在主线程,不然程序会被堵塞的。

  线程的处境: Running

    个人以为那种艺术相比较好。

  对于地点的代码不想做过多解释,只说一下Thread.CurrentThread得到的是试行业前代码的线程。

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

  叁.壹.1异步调用线程

**

  这里先说一下前台线程与后台线程。前台线程能阻碍应用程序的停下,既直到全部前台线程终止后才会透彻关闭应用程序。而对后台线程而言,当有着前台线程终止时,后台线程会被机关甘休,不论后台线程是或不是正在实行任务。暗中同意情形下通过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(“全体任务达成”);
        }
    }

  下边先看1个例子,该例子创立三个次线程实践打字与印刷数字的义务,而主线程则干任何的事,两者同时拓展,互不困扰。

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一运转完后,还是可以体现出“全部职分完结”的提醒消息,可是counter二和counter3还尚未运维。为了免去这些隐患,能够将increment方法从run中移除,将其置于ThreadCounter的构造方法中,在此时,increment方法中的lock也足以去掉了。代码如:
        public ThreadCounter(int ms)
        {
            this.ms = ms;
            increment();
        }

  using System.Windows.Forms;

    运维方面包车型大巴主次后,将展现如图二的结果。

  namespace MultiThread

亚洲必赢官网 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();

  }

  }

  }

  程序运营后会看到2个窗口弹出,如图所示,同时间调整制台窗口也在相连的显得数字。

    亚洲必赢官网 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 命名空间下的三个寄托,其注明是 public delegate void
ThreadStart(),指向不带参数、重回值为空的不二诀窍。所以当使用 ThreadStart
时,对应的线程就只可以调用不带参数、重临值为空的方法。那非要指向含参数的法子吗?在System.Threading命名空间下还有多少个ParameterizedThreadStart 委托,其宣称是
public delegate void ParameterizedThreadStart(object obj),能够针对含
object 类型参数的点子,这里并非忘了 object
可是全体连串的父类哦,有了它就可以经过创办种种自定义类型,如组织、类等传递繁多参数了,那里就不再举例表明了。

  3.一.二并发难点

  那里再经过1个例证让我们具体体会一下前方聊到的现身难题,然后再介绍线程同步。

  using System;

  using System.Threading;

  namespace MultiThread1

  {

  class Class

  {

  static void Main(string[] args)

  {

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

  //制造四个打字与印刷对象实例

  Printer printer = new Printer();

  //声澳优(Ausnutria Hyproca)含多少个线程对象的数组

  Thread[] threads = new Thread[10];

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

  {

  //将每2个线程都对准printer的PrintNumbers()方法

  threads[i]亚洲必赢官网, = new Thread(new ThreadStart(printer.PrintNumbers));

  //给每3个线程编号

  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();

  }

  }

  }

  上边的例证中,主线程产生的13个线程同时做客同一个指标实例printer的章程PrintNumbers(),由于尚未锁定共享能源(注意,那里是指调节台),所以在PrintNumbers()输出到调控台以前,调用PrintNumbers()的线程很或者被挂起,但不通晓怎么样时候(或是还是不是有)挂起,导致获得不可预测的结果。如下是四个分歧的结果(当然,读者的运维结果或然会是别的意况)。

    亚洲必赢官网 4

  情形一

    亚洲必赢官网 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();

  }

  }

  }

  }

  同步后进行结果如下:

    亚洲必赢官网 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模同样。

  三.二因而信托塑造拾二线程应用程序

  在看上面包车型大巴始末时供给对信托有自然的垂询,若是不通晓的话推荐参考一下今日头条张子阳的《C# 中的委托和事件》,里面对信托与事件进行由表及里的较系统的执教: http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/903360.html。

  那里先举2个有关信托的简练例子,具体解释见注释:

  using System;

  namespace MultiThread

  {

  //定义三个针对性包括四个int型参数、重返值为int型的函数的委托

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

  class Program

  {

  static void Main(string[] args)

  {

  //创设1个指向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

 

 

 

  三.二.1线程异步

  先说爱他美(Aptamil)下,那里不打算讲授委托线程异步或合伙的参数传递、获取再次来到值等,只是做个一般的始发而已,就算后边有时间了再其余写一篇有关多线程中参数字传送递、获取重回值的小说。

  注意观看地点的事例会发现,直接行使委托实例 pAddOp(10, 五)
就调用了求和格局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是线程的唯1标示

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

  //模拟三个经过,停留伍秒

  Thread.Sleep(5000);

  int sum = x + y;

  return sum;

  }

  }

  }

  运维结果如下:

  ******* 委托异步线程 四个线程“同时”职业 *********

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

  Main()方法中执行其余职务……..

  调用求和艺术 Add()的线程ID是: 7.

  10 + 10 = 20.

  三.二.二线程同步

  委托中的线程同步首要涉及到地方运用的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是线程的唯1标示

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

  //模拟三个进程,停留伍秒

  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组件位于工具箱中,用于方便的创导线程异步的程序。新建三个WindowsForms应用程序,分界面如下:

    亚洲必赢官网 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.总结

  本文从线程、进度、应用程序的关联开始,介绍了有的关于四线程的基本概念,同时解说了线程异步、线程同步及出现难点等。最终从使用角度出发,介绍了什么通过System.Threading命名空间的类、委托和BackgroundWorker组件等三种花招营造二10二十四线程应用程序。

网站地图xml地图