创建线程,一创办线程

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是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(100); } 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
扶助线程:5
辅助线程:陆
帮衬线程:七
救助线程:8
补助线程:9
扶持线程甘休.
主线程甘休

上一篇:C#线程连串讲座(1):BeginInvoke和EndInvoke方法

  随着双核、四核等多核处理器的放大,多核处理器或超线程单核处理器的Computer已很广阔,基于多核处理的编制程序技能也初步受到程序员们普遍关怀。那之中三个根本的地点正是营造八线程应用程序(因为不使用二十四线程的话,开辟职员就不可能丰富发挥多核处理器的兵不血刃质量)。

1、            
Thread类的中坚用法

  本文针对的是创设基于单核Computer的二十多线程应用程序,意在介绍十二线程相关的基本概念、内涵,以及哪些通过System.Threading命名空间的类、委托和BackgroundWorker组件等二种花招构建多线程应用程序。

经过System.Threading.Thread类能够开头新的线程,并在线程仓库中运维静态或实例方法。能够因而Thread类的的构造方法传递多个无参数,并且不重临值(重临void)的委托(ThreadStart),那些委托的概念如下:

  本文假诺能为刚接触八线程的朋友起到投砾引珠的机能也就春风得意了。当然,本人才疏学浅,文中难免会有不足或不当的地点,恳请各位朋友多多指引。

[ComVisibleAttribute(true)]

  一.驾驭拾二线程

public delegate void ThreadStart()

  大家普通明白的应用程序正是三个*.exe文件,当运行*.exe应用程序未来,系统会在内部存款和储蓄器中为该程序分配一定的空中,同时加载一些该程序所需的能源。其实这就足以称为创制了二个进度,能够通过Windows任务管理器查看这几个历程的有关音信,如影像名称、用户名、内部存储器使用、PID(唯一的长河标示)等,如图下所示。

咱俩得以通过如下的格局来树立并运维贰个线程。

    

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

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

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 thread三 = new Thread(delegate() { Console.WriteLine(“匿名委托”); });
thread3.Start();

  Application.Run(new MainForm());

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

  }

    个中拉姆da表达式前边的(
)表示不曾子舆数。

  进度会蕴藏一个进入此入口的线程,大家誉为主线程。此中,天性
[STAThread]
提醒应用程序的默许线程模型是单线程单元(相关音讯可参考http://msdn.microsoft.com/en-us/library/system.stathreadattribute(VS.71).aspx.aspx))。只含有贰个主线程的进度是线程安全的,也正是程序仅有一条工作线,唯有成就了前头的天职本领执行排在前面包车型客车职务。

    为了分化差别的线程,仍可感觉Thread类的Name属性赋值,代码如下:

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

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

  为了制服单线程的这些毛病,Win3二API能够让主线程再次创下立别的的次线程,但不论是是主线程照旧次线程都是经过中独立的实践单元,能够而且访问共享的多少,那样就有了三十二线程这么些概念。

    假诺将方面thread1至thread五停放一齐施行,由于系统对线程的调度不一致,输出的结果是不定的,如图一是一种只怕的出口结果。

  相信到那,应该对二十四线程有个比较感性的认识了。但小编在那要唤醒一下,基于单核Computer的八线程其实只是操作系统施展的一个障眼法而已(但那不会搅乱大家知晓创设三十二线程应用程序的笔触),他并无法收缩完结全部任务的时日,有时反而还会因为运用过多的线程而下落品质、延长时间。之所以那样,是因为对此单CPU来讲,在三个单位时间(也称时间片)内,只好实行三个线程,即只好干一件事。当3个线程的年月片用完时,系统会将该线程挂起,下一个小时内再实践另2个线程,如此,CPU以时间片为距离在多少个线程之间轮换施行运算(其实那里还与种种线程的优先级有关,等级高的会优先处理)。由于交替时间距离十分的短,所以导致了11线程都在“同时”职业的假象;而若是线程数目过多,由于系统挂起线程时要记录线程当前的意况数据等,那样又势必会降低程序的1体化质量。但对此这几个,多核处理器就能从精神上(真正的同时职业)进步程序的执行功用。

美高梅开户网址 1

  二. 线程异步与线程同步

                                                                 图1

  从线程试行任务的方法上得以分成线程同步和线程异步。而为了便利清楚,前面描述中用“同步线程”指代与线程同步相关的线程,一样,用“异步线程”表示与线程异步相关的线程。

二、
定义二个线程类

  线程异步正是竭泽而渔类似前边提到的推行耗费时间任务时分界面控件不能利用的主题素材。如创立3个次线程去尤其实行耗费时间的天职,而别的如分界面控件响应那样的义务交给另1个线程实施(往往由主线程施行)。那样,四个线程之间通过线程调度器短期(时间片)内的切换,就模拟出八个义务“同时”被试行的效用。

    大家能够将Thread类封装在一个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个线程(前边介绍的线程间的切换),所以当线程a对共享数据D的造访(修改、删除等操作)完结在此之前被挂起,而此时线程b又刚刚去拜访数据D,那么线程b访问的则是3个不平静的数量。那样就会发出非凡麻烦察觉bug,由于是自由爆发的,发生的结果是不可预测的,那样样的bug也都很难再现和调整。那正是出新难题。

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

  为了缓解十二线程共同访问多少个共享能源(也称互斥访问)时发生的产出难题,线程同步就应运而生了。线程同步的机理,简单来讲,便是谨防三个线程同时做客有个别共享的能源。做法很简短,标志访问某共享能源的那有个别代码,当程序运营到有暗记的地点时,CLXC60(具体是怎样能够先不管,只要知道它能决定就行)对各线程实行调控:借使已无线程在走访一财富,CL瑞鹰就会将别的访问那一财富的线程挂起,直到前1线程截至对该财富的访问。那样就确认保证了同权且间唯有三个线程访问该能源。打个借使,就好像某财富位居只有一独石桥相连的孤岛上,倘若要采纳该财富,我们就得排队,2个三个来,前面包车型客车回来了,下贰个再去,前面包车型地铁没赶回,前边的就原地待命。

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

  那里只是把基本的概念及原理做了四个简便的阐释,不至于看后边的次第时糊里凌乱的。具体怎么编写代码,下边包车型地铁段落将做详细介绍。

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

 

  static void Main(string[] args)
  {

 

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

  叁.开立102线程应用程序

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

  那里做三个简便的验证:上边首要透过介绍通过System.Threading命名空间的类、委托和BackgroundWorker组件三种分裂的手段营造八线程应用程序,具体会从线程异步和线程同步五个方面来论述。

三、    
为线程传递参数

  三.一因此System.Threading命名空间的类创设

Thread类有贰个带参数的寄托项目标重载格局。这几个委托的定义如下:

  在.NET平台下,System.Threading命名空间提供了成百上千品类来营造二十十2线程应用程序,能够说是专为四线程服务的。由于本文仅是想起到三个“进行试探”的效果,所以对于那壹块不会追究过多、过深,首要运用System.Threading.Thread类。

[ComVisibleAttribute(false)]

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

public delegate void ParameterizedThreadStart(Object obj)

  using System;

其1Thread类的构造方法的定义如下:

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

4、    
前台和后台线程

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

    使用Thread建立的线程暗许处境下是前台线程,在进程中,只要有一个前台线程未脱离,进程就不会告1段落。主线程正是三个前台线程。而后台线程不管线程是或不是得了,只要具有的前台线程都退出(包罗健康退出和13分退出)后,进度就会活动终止。1般后台线程用于拍卖时间较短的职责,如在一个Web服务器中得以行使后台线程来处理客户端发过来的伸手音讯。而前台线程1般用于拍卖必要长日子等待的职责,如在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次,这一个计数器就加一,销毁引用就减一,假使引用数为0,则垃圾搜聚器就会对那个引用数为0的对象开始展览回收。

  ************** 突显当前线程的相关音讯
*************

措施1:线程计数器

  线程的名字:主线程

线程也得以行使计数器的主意,即为全数必要监视的线程设二个线程计数器,每起初多少个线程,在线程的施行办法中为那些计数器加1,即使某些线程甘休(在线程施行格局的末梢为这几个计数器减一),为这几个计数器减1。然后再初阶贰个线程,按着一定的时辰间隔来监视这么些计数器,如是棕个计数器为0,表明具备的线程都得了了。当然,也可以不用那么些监视野程,而在每一个做事线程的终极(在为计数器减一的代码的背后)来监视这一个计数器,相当于说,每三个办事线程在脱离在此之前,还要承受检查实验这么些计数器。使用那种方法毫无忘了一起这一个计数器变量啊,不然会发生意料之外的结果。

  线程是还是不是运维? True

方法二:使用Thread.join方法

  线程的优先级: Normal

join方法只有在线程截至时才继续试行下边的说话。能够对每二个线程调用它的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;

   
上边的代码就算在大部分的时候能够符合规律干活,但却存在叁个隐患,就是只要有个别线程,如果是counter壹,在运营后,由于①些原因,别的的线程并没有运转,在那种景况下,在counter1运维完后,依然能够来得出“全数职分完成”的提醒音讯,然则counter二和counter三还尚未运维。为了祛除这几个隐患,能够将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();

  }

  }

  }

  程序运转后会看到1个窗口弹出,如图所示,同时决定台窗口也在持续的显得数字。

    美高梅开户网址 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命名空间下还有1个ParameterizedThreadStart 委托,其宣称是
public delegate void ParameterizedThreadStart(object obj),能够本着含
object 类型参数的章程,那里并非忘了 object
不过具备品种的父类哦,有了它就足以透过创办种种自定义类型,如组织、类等传递多数参数了,那里就不再举例表达了。

  3.一.二并发问题

  这里再通过2个例证让我们具体体会一下前方提起的产出难题,然后再介绍线程同步。

  using System;

  using System.Threading;

  namespace MultiThread1

  {

  class Class

  {

  static void Main(string[] args)

  {

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

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

  Printer printer = new Printer();

  //声宾博(Dumex)含陆个线程对象的数组

  Thread[] threads = new Thread[10];

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

  {

  //将每一个线程都指向printer的PrintNumbers()方法

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

  //给每1个线程编号

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

  }

  }

  }

  上面包车型大巴例证中,主线程发生的11个线程同时做客同3个目的实例printer的措施PrintNumbers(),由于并未有锁定共享财富(注意,那里是指调控台),所以在PrintNumbers()输出到调整台在此之前,调用PrintNumbers()的线程很恐怕被挂起,但不晓得怎么时候(或是还是不是有)挂起,导致得到不可预测的结果。如下是多少个不等的结果(当然,读者的周转结果大概会是此外情状)。

    美高梅开户网址 4

  情形一

    美高梅开户网址 5

  情形二

 

 

 

  3.一.3线程同步

  线程同步的走访形式也称之为阻塞调用,即未有进行完义务不回去,线程被挂起。能够动用C#中的lock关键字,在此关键字范围类的代码都将是线程安全的。lock关键字需定义贰个标志,线程进入锁定范围是必须赚取那个标志。当锁定的是3个实例级对象的私有方法时选拔方法自身所在对象的引用就足以了,将上边例子中的打字与印刷类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);

  }

  }

  }

  输出结果与地点的均等。

  3.二经过信托塑造十二线程应用程序

  在看下边包车型大巴剧情时讲求对信托有必然的摸底,要是不通晓的话推荐参考一下天涯论坛张子阳的《C# 中的委托和事件》,里面对信托与事件开始展览由表及里的较系统的授课: http://www.cnblogs.com/JimmyZhang/archive/2007/09/23/903360.html。

  那里先举贰个关于信托的简便例子,具体表达见注释:

  using System;

  namespace MultiThread

  {

  //定义一个针对性包蕴四个int型参数、重返值为int型的函数的信托

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

  class Program

  {

  static void Main(string[] args)

  {

  //成立2个指向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线程异步

  先说澳优下,那里不打算批注委托线程异步或联手的参数传递、获取重回值等,只是做个常见的开头而已,假若前面有时间了再别的写1篇有关八线程中参数字传送递、获取重临值的篇章。

  注意观看地点的例证会意识,直接采纳委托实例 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(“******* 委托异步线程 四个线程“同时”职业
*********”);

  //展现主线程的唯1标示

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

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

  Thread.Sleep(5000);

  int sum = x + y;

  return sum;

  }

  }

  }

  运转结果如下:

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

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

  Main()方法中实行其它义务……..

  调用求和措施 Add()的线程ID是: 七.

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

  //模拟多个进程,停留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组件位于工具箱中,用于方便的创立线程异步的先后。新建1个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;

  //停留5秒,模拟耗费时间职责

  Thread.Sleep(5000);

  //返回值

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

  }

  //当backgroundWorker1的DoWork中的代码推行完后会触发该事件

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

  private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)

  {

  //显示运算结果

  MessageBox.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组件等三种花招创设拾二线程应用程序。

发表评论

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

网站地图xml地图