C#多线程

前言

根据上一节中http://www.cnblogs.com/aehyok/archive/2013/05/02/3054615.html对多线程的入门了解。本节就来探讨一下简单的使用多线程。

使用多线程  

线程用Thread类来创建, 通过ThreadStart委托来指明方法从哪里开始运行,下面是ThreadStart委托如何定义的:

public delegate void ThreadStart();

调用Start方法后,线程开始运行,线程一直到它所调用的方法返回后结束。下面是一个例子,使用了C#的语法创建TheadStart委托:

    class Program
    {
        static void Main(string[] args)
        {
            System.Threading.Thread thread = new System.Threading.Thread(Go);
            thread.Start();
            Go();
            Console.ReadLine();

        }

        static void Go() { Console.WriteLine("hello!"); }
    }

在这个例子中,线程t执行Go()方法,大约与此同时主线程也调用了Go(),结果是两个几乎同时hello被打印出来:

一个线程可以通过C#堆委托简短的语法更便利地创建出来:

              System.Threading.Thread t = new System.Threading.Thread (delegate() { Console.WriteLine ("Hello!"); });
              t.Start();

线程有一个IsAlive属性,在调用Start()之后直到线程结束之前一直为true。一个线程一旦结束便不能重新开始了。

将数据传入ThreadStart中

 话又说回来,在上面的例子里,我们想更好地区分开每个线程的输出结果,让其中一个线程输出大写字母。我们传入一个状态字到Go中来完成整个任务,但我们不能使用ThreadStart委托,因为它不接受参数,所幸的是,.NET framework定义了另一个版本的委托叫做ParameterizedThreadStart, 它可以接收一个单独的object类型参数:

namespace System.Threading
{
    // 摘要:
    //     表示在 System.Threading.Thread 上执行的方法。
    //
    // 参数:
    //   obj:
    //     包含该线程过程的数据的对象。
    [ComVisible(false)]
    public delegate void ParameterizedThreadStart(object obj);
}

示例

        static void Main(string[] args)
        {
            System.Threading.Thread thread = new System.Threading.Thread(Go);
            thread.Start(true); 
            Go(false);
            Console.ReadLine();
        }

        static void Go(object upperCase)
        {
            bool upper = (bool)upperCase;
            Console.WriteLine(upper ? "HELLO!" : "hello!");
        }

在整个例子中,编译器自动推断出ParameterizedThreadStart委托,因为Go方法接收一个单独的object参数,就像这样写:在整个例子中,编译器自动推断出ParameterizedThreadStart委托,因为Go方法接收一个单独的object参数,就像这样写:

            System.Threading.Thread thread = new System.Threading.Thread(Go);
            thread.Start(true); 

ParameterizedThreadStart的特性是在使用之前我们必需对我们想要的类型(这里是bool)进行装箱操作,并且它只能接收一个参数。

  一个替代方案是使用一个匿名方法调用一个普通的方法如下:

    class Program
    {
        static void Main()
        {
            System.Threading.Thread t = new System.Threading.Thread(delegate() { WriteText("Hello"); });
            t.Start();
            Console.ReadLine();
        }
        static void WriteText(string text) { Console.WriteLine(text); }
    }

优点是目标方法(这里是WriteText),可以接收任意数量的参数,并且没有装箱操作。不过这需要将一个外部变量放入到匿名方法中,像下面的一样:

    class Program
    {
        static void Main()
        {
            string text = "Before";
            System.Threading.Thread t = new System.Threading.Thread(delegate() { WriteText(text); });
            text = "aehyok";
            t.Start();
            Console.ReadLine();
        }
        static void WriteText(string text) { Console.WriteLine(text); }
    }

匿名方法打开了一种怪异的现象,当外部变量被后来的部分修改了值的时候,可能会透过外部变量进行无意的互动。有意的互动(通常通过字段)被认为是足够了!一旦线程开始运行了,外部变量最好被处理成只读的——除非有人愿意使用适当的锁。

另一种较常见的方式是将对象实例的方法而不是静态方法传入到线程中,对象实例的属性可以告诉线程要做什么,如下列重写了原来的例子:

    class Program
    {
        bool upper;
        static void Main()
        {
            Program instance1 = new Program();

            instance1.upper = true;

            System.Threading.Thread t = new System.Threading.Thread(instance1.Go);
            t.Start();
            Program instance2 = new Program();
            instance2.Go();
            Console.ReadLine();
        }
        void Go() { Console.WriteLine(upper ? "HELLO!" : "hello!"); }
    }

命名线程

  线程可以通过它的Name属性进行命名,这非产有利于调试:可以用Console.WriteLine打印出线程的名字,Microsoft Visual Studio可以将线程的名字显示在调试工具栏的位置上。线程的名字可以在被任何时间设置——但只能设置一次,重命名会引发异常。

  程序的主线程也可以被命名,下面例子里主线程通过CurrentThread命名:

        static void Main()
        {
            System.Threading.Thread.CurrentThread.Name = "main";
            System.Threading.Thread worker = new System.Threading.Thread(Go);
            worker.Name = "worker";
            worker.Start();
            Go();
            Console.ReadLine();
        }

        static void Go()
        {

            Console.WriteLine("Hello from " + System.Threading.Thread.CurrentThread.Name);

        }

还有几点下节继续。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏GreenLeaves

反射基础入门篇

1、简介 Reflection,中文翻译为反射。.Net的应用程序由以下几个部分组成: a、程序集(assembly) b、模块(moudle) c、类型(cl...

19460
来自专栏码云1024

C#反射

30630
来自专栏用户3030674的专栏

Java中Json解析

首先准备一个JSON格式的字符串 * String JsonStr = "{object:{persons:" + "[{name:'呵呵',im...

40820
来自专栏林德熙的博客

win10 uwp unix timestamp 时间戳 转 DateTime

有时候需要把网络的 unix timestamp 转为 C# 的 DateTime ,在 UWP 可以如何转换?

7110
来自专栏飞扬的花生

集合中随机取不重复的索引

有时候希望从一个集合中随机取n个元素不重复 那么就取到这n个数字的索引 public static int[] GetRandomArray(int Numb...

33280
来自专栏大内老A

通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典

在本系列的前面两篇文章(《简单类型+复杂类型》、《数组》)我们通过创建的实例程序模拟了ASP.NET MVC默认使用的DefaultModelBinder对简单...

30770
来自专栏林德熙的博客

dot net double 数组转 float 数组

本文告诉大家如果遇到 double 数组转 float 数组千万不要使用 Cast ,一般都使用 select 强转。

11110
来自专栏Jackson0714

【问题与思考】1+"1"=?

30630
来自专栏程序你好

理解C#语言中相等Equality 和唯一 Identity

10520
来自专栏前端侠2.0

学习表达式树笔记 原

文章地址:  http://www.cnblogs.com/Ninputer/archive/2009/08/28/expression_tree1.html

10320

扫码关注云+社区

领取腾讯云代金券