using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//成立线程
//两组范围为1-10的数字会随机交叉输出,表达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
类拥用五个重载的构造函数,常用的三个收下三个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(“帮助线程截止.”); } }

**本文为原创,如需转发,请表明我和出处,多谢!

 

运作结果:

1成立线程,线程连串讲座。**

引言

主线程开首
主线程:a
协助线程初步…
扶植线程:0
主线程:b
主线程:c
支持线程:一
主线程:d
主线程:e
帮衬线程:二
主线程:f
接济线程:三
主线程:g
主线程:h
扶助线程:4
主线程:i
主线程:j
帮扶线程:5
帮衬线程:陆
援救线程:7
救助线程:捌
帮助线程:9
扶持线程甘休.
主线程停止

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

  随着双核、四核等多核处理器的放大,多核处理器或超线程单核处理器的微型Computer已很宽泛,基于多核处理的编制程序本事也初始碰到程序员们普及关怀。那在那之中二个至关主要的下边正是营造四线程应用程序(因为不选拔二十多线程的话,开辟人士就无法丰硕发挥多核处理器的精锐质量)。

一、            
Thread类的为主用法

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

透过System.Threading.Thread类能够起来新的线程,并在线程货仓中运营静态或实例方法。能够通过Thread类的的构造方法传递1个无参数,并且不重回值(重回void)的信托(ThreadStart),那一个委托的概念如下:

  本文若是能为刚接触二十多线程的朋友起到一得之见的效果也就心旷神怡了。当然,本人才疏学浅,文中难免会有欠缺或不当的地方,恳请各位朋友多多指引。

[ComVisibleAttribute(true)]

  1.亮堂多线程

public delegate void ThreadStart()

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

大家得以透过如下的章程来树立并运维一个线程。

    

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

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

namespace MyThread
{
    class Program
    {
        public static void myStaticThreadMethod()
        {
            Console.WriteLine(“myStaticThreadMethod”);
        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(myStaticThreadMethod);
            thread一.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();

   
假诺读者的艺术很简短,或出来某种指标,也足以因而匿名委托或拉姆da表明式来为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))。只含有贰个主线程的历程是线程安全的,相当于程序仅有一条工作线,唯有成就了前方的任务技艺实践排在前边的天职。

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

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

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

  为了克服单线程的那么些毛病,Win3二API能够让主线程再创造别的的次线程,但无论是是主线程依旧次线程都以经过中单独的奉行单元,能够而且访问共享的数码,这样就有了二十四线程那些概念。

    若是将上边thread一至thread五置于一同实践,由于系统对线程的调度不相同,输出的结果是不定的,如图1是一种大概的输出结果。

  相信到那,应该对多线程有个比较感性的认识了。但小编在那要提醒一下,基于单核Computer的102线程其实只是操作系统施展的3个障眼法而已(但那不会震惊大家通晓创设十二线程应用程序的思路),他并不能够收缩达成具备任务的大运,有时反而还会因为使用过多的线程而减低品质、延长时间。之所以那样,是因为对于单CPU来讲,在2个单位时间(也称时间片)内,只好实践3个线程,即只好干一件事。当1个线程的时日片用完时,系统会将该线程挂起,下二个时日内再推行另一个线程,如此,CPU以时间片为距离在七个线程之间交替实施运算(其实那里还与种种线程的优先级有关,等第高的会优先处理)。由于交替时间距离异常的短,所以形成了1一线程都在“同时”工作的假象;而一旦线程数目过多,由于系统挂起线程时要记录线程当前的情景数据等,那样又势必会下降程序的完好质量。但对此那么些,多核处理器就能从实质上(真正的还要职业)提升程序的施行功效。

金沙注册送58 1

  二. 线程异步与线程同步

                                                                 图1

  从线程推行职务的措施上能够分成线程同步和线程异步。而为了便于掌握,后边描述中用“同步线程”指代与线程同步相关的线程,同样,用“异步线程”表示与线程异步相关的线程。

贰、
定义三个线程类

  线程异步正是缓解类似前面提到的推行耗费时间职责时分界面控件不能够使用的标题。如成立1个次线程去专门实践耗费时间的职分,而别的如分界面控件响应那样的天职交给另3个线程试行(往往由主线程实践)。这样,两个线程之间通过线程调度器短期(时间片)内的切换,就模拟出多少个职务“同时”被实践的功力。

    大家得以将Thread类封装在贰个MyThread类中,以使任何从MyThread继承的类都装有102线程本事。MyThread类的代码如下:

  线程异步往往是经过创办四个线程实行多少个职责,五个职业线同时开工,类似多辆在广泛的公路上相互的轿车还要进步,互不干扰(读者要知道,本质上并不曾“同时”,仅仅是操作系统玩的三个障眼法。但那几个障眼法却对加强大家的次第与用户之间的互动、以及抓好程序的友好性很有用,不是吧)。

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

  前边提到,线程都是独自的实践单元,能够访问共享的多寡。也便是说,在2个具有四个次线程的顺序中,每一个线程都能够访问同1个共享的数目。再稍加思量你会意识那样可能会出标题:由于线程调度器会自由的挂起某一个线程(前边介绍的线程间的切换),所以当线程a对共享数据D的造访(修改、删除等操作)完结以前被挂起,而此时线程b又恰好去拜访数据D,那么线程b访问的则是3个不安静的多寡。那样就会时有产生格外麻烦察觉bug,由于是专擅产生的,发生的结果是不行预测的,这样样的bug也都很难再次出现和调剂。那正是出新难题。

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

  为了缓解四线程共同访问二个共享能源(也称互斥访问)时发生的出现难点,线程同步就涌出了。线程同步的机理,简来说之,便是谨防多少个线程同时做客某些共享的能源。做法很简单,标志访问某共享财富的那部分代码,当程序运营到有标记的地点时,CLCR-V(具体是什么样能够先不管,只要通晓它能决定就行)对各线程进行调节:假如已有线程在走访1财富,CL翼虎就会将别的访问那一财富的线程挂起,直到前一线程截止对该财富的访问。那样就保证了同暂时间唯有三个线程访问该财富。打个比方,就好像某财富放在只有一独石桥相连的半壁江山上,如若要利用该财富,大家就得排队,叁个贰个来,前边的回到了,下二个再去,前边的没回来,后边的就原地待命。

   
能够用上边包车型地铁代码来利用MyThread类。

  那里只是把中央的概念及原理做了3个大致的阐释,不至于看前面包车型客车先后时糊里凌乱的。具体哪些编写代码,上边包车型客车段落将做详细介绍。

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

 

  static void Main(string[] args)
  {

 

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

  叁.创立二10十二线程应用程序

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

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

叁、    
为线程传递参数

  三.一通过System.Threading命名空间的类创设

Thread类有3个带参数的信托项目标重载形式。那个委托的概念如下:

  在.NET平台下,System.Threading命名空间提供了众多门类来创设二十四线程应用程序,能够说是专为四线程服务的。由于本文仅是回看到三个“投砾引珠”的机能,所以对于那一块不会追究过多、过深,首要选拔System.Threading.Thread类。

[ComVisibleAttribute(false)]

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

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;

   
要是选择在其次节定义的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个前台线程未脱离,进度就不会停下。主线程正是五个前台线程。而后台线程不管线程是或不是得了,只要具备的前台线程都退出(包涵常规退出和越发退出)后,进程就会活动终止。壹般后台线程用于拍卖时间较短的职分,如在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、  
判断几个线程是不是都终止的二种办法

  输出结果如下:

金沙注册送58 ,规定所无线程是或不是都实现了劳作的点子有为数不少,如能够应用类似于对象计数器的主意,所谓目的计数器,正是三个指标被引述二回,那么些计数器就加1,销毁引用就减一,假如引用数为0,则垃圾搜罗器就会对这几个引用数为0的靶子进行回收。

  ************** 显示当前线程的连锁音信
*************

主意壹:线程计数器

  线程的名字:主线程

线程也能够动用计数器的点子,即为全体须求监视的线程设二个线程计数器,每发轫三个线程,在线程的施行措施中为那么些计数器加一,若是有些线程停止(在线程实施办法的尾声为这么些计数器减一),为那一个计数器减一。然后再起来七个线程,按着一定的年华距离来监视这么些计数器,如是棕个计数器为0,表达全部的线程都得了了。当然,也能够毫无那个监视野程,而在每3个办事线程的最终(在为计数器减一的代码的末尾)来监视那么些计数器,也正是说,每3个职业线程在退出在此以前,还要承担检查评定这些计数器。使用那种措施毫无忘了一块儿那几个计数器变量啊,不然会生出出人意料的后果。

  线程是还是不是运营? True

方法二:使用Thread.join方法

  线程的事先级: Normal

join方法唯有在线程甘休时才继续实践上面包车型地铁语句。能够对每2个线程调用它的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;

   
上边的代码纵然在多数的时候能够健康工作,但却存在三个隐患,正是1旦有些线程,借使是counter一,在运作后,由于某个原因,别的的线程并未运转,在那种境况下,在counter一运转完后,依旧能够显得出“全数职务完成”的提示音信,可是counter二和counter叁还从未运营。为了解决那些隐患,能够将increment方法从run中移除,将其内置ThreadCounter的构造方法中,在这时,increment方法中的lock也能够去掉了。代码如:
        public ThreadCounter(int ms)
        {
            this.ms = ms;
            increment();
        }

  using System.Windows.Forms;

    运维方面包车型客车次序后,将呈现如图2的结果。

  namespace MultiThread

金沙注册送58 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个窗口弹出,如图所示,同时决定台窗口也在相连的显得数字。

    金沙注册送58 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 命名空间下的2个寄托,其注明是 public delegate void
ThreadStart(),指向不带参数、再次来到值为空的模式。所以当使用 ThreadStart
时,对应的线程就不得不调用不带参数、再次回到值为空的法子。这非要指向含参数的办法吗?在System.Threading命名空间下还有1个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(“********* 并发难题演示
***************”);

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

  Printer printer = new Printer();

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

  Thread[] threads = new Thread[10];

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

  {

  //将每八个线程都指向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();

  }

  }

  }

  上边的例证中,主线程产生的13个线程同时做客同一个目标实例printer的方法PrintNumbers(),由于尚未锁定共享财富(注意,那里是指调控台),所以在PrintNumbers()输出到调控台在此以前,调用PrintNumbers()的线程很恐怕被挂起,但不领会如几时候(或是还是不是有)挂起,导致获得不可预测的结果。如下是七个例外的结果(当然,读者的运转结果或许会是其它意况)。

    金沙注册送58 4

  情形一

    金沙注册送58 5

  情形二

 

 

 

  三.一.叁线程同步

  线程同步的造访格局也称之为阻塞调用,即没有进行完职责不回来,线程被挂起。能够行使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();

  }

  }

  }

  }

  同步后进行结果如下:

    金沙注册送58 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);

  }

  }

  }

  输出结果与地方的同一。

  三.二经过委托营造八线程应用程序

  在看上面的剧情时须要对信托有早晚的摸底,如若不明白的话推荐参考一下博客园张子阳的《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)

  {

  //创立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

 

 

 

  3.二.一线程异步

  先说美素佳儿(Karicare)下,那里不打算解说委托线程异步或联合的参数字传送递、获取再次来到值等,只是做个常备的起来而已,如若前面有时光了再别的写一篇有关二十十二线程中参数字传送递、获取重返值的文章。

  注意观望地点的例证会意识,直接选择委托实例 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是线程的唯1标示

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

  //模拟一个进度,停留伍秒

  Thread.Sleep(5000);

  int sum = x + y;

  return sum;

  }

  }

  }

  运转结果如下:

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

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

  Main()方法中施行此外职责……..

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

  10 + 10 = 20.

  叁.二.二线程同步

  委托中的线程同步首要涉及到上边运用的pAddOp.BeginInvoke(十, 拾, 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组件位于工具箱中,用于方便的创始线程异步的次序。新建二个WindowsForms应用程序,分界面如下:

    金沙注册送58 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;

  }

  //当backgroundWorker一的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地图