C#多线程

简介: 前言 根据上一节中http://www.cnblogs.com/aehyok/archive/2013/05/02/3054615.html对多线程的入门了解。本节就来探讨一下简单的使用多线程。 使用多线程   线程用Thread类来创建, 通过ThreadStart委托来指明方法从哪里开始运行,下面是ThreadStart委托如何定义的: public delegate void ThreadStart(); 调用Start方法后,线程开始运行,线程一直到它所调用的方法返回后结束。

前言

根据上一节中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);

        }

还有几点下节继续。

 

目录
相关文章
|
SQL 开发框架 安全
C#编程与多线程处理
【4月更文挑战第21天】探索C#多线程处理,提升程序性能与响应性。了解C#中的Thread、Task类及Async/Await关键字,掌握线程同步与安全,实践并发计算、网络服务及UI优化。跟随未来发展趋势,利用C#打造高效应用。
514 3
|
Java 调度 C#
C#学习系列相关之多线程(一)----常用多线程方法总结
C#学习系列相关之多线程(一)----常用多线程方法总结
257 0
|
数据采集 XML JavaScript
C# 中 ScrapySharp 的多线程下载策略
C# 中 ScrapySharp 的多线程下载策略
|
机器学习/深度学习 监控 算法
局域网行为监控软件 C# 多线程数据包捕获算法:基于 KMP 模式匹配的内容分析优化方案探索
本文探讨了一种结合KMP算法的多线程数据包捕获与分析方案,用于局域网行为监控。通过C#实现,该系统可高效检测敏感内容、管理URL访问、分析协议及审计日志。实验表明,相较于传统算法,KMP在处理大规模网络流量时效率显著提升。未来可在算法优化、多模式匹配及机器学习等领域进一步研究。
318 0
|
安全 数据库连接 API
C#一分钟浅谈:多线程编程入门
在现代软件开发中,多线程编程对于提升程序响应性和执行效率至关重要。本文从基础概念入手,详细探讨了C#中的多线程技术,包括线程创建、管理及常见问题的解决策略,如线程安全、死锁和资源泄露等,并通过具体示例帮助读者理解和应用这些技巧,适合初学者快速掌握C#多线程编程。
419 1
|
并行计算 算法 C#
C# Mandelbrot和Julia分形图像生成程序更新到2010-9-14版 支持多线程计算 多核处理器
此文档是一个关于分形图像生成器的介绍,作者分享了个人开发的M-J算法集成及色彩创新,包括源代码和历史版本。作者欢迎有兴趣的读者留言交流,并提供了邮箱(delacroix_xu@sina.com)以分享资源。文中还展示了程序的发展历程,如增加了真彩色效果、圈选放大、历史记录等功能,并分享了几幅精美的分形图像。此外,还提到了程序的新特性,如导入ini文件批量输出图像和更新一批图片的功能。文档末尾附有多张程序生成的高分辨率分形图像示例。
|
大数据 C#
C#实现多线程的几种方式
C#实现多线程的几种方式
208 1
|
安全 C# 开发者
【C# 多线程编程陷阱揭秘】:小心!那些让你的程序瞬间崩溃的多线程数据同步异常问题,看完这篇你就能轻松应对!
【8月更文挑战第18天】多线程编程对现代软件开发至关重要,特别是在追求高性能和响应性方面。然而,它也带来了数据同步异常等挑战。本文通过一个简单的计数器示例展示了当多个线程无序地访问共享资源时可能出现的问题,并介绍了如何使用 `lock` 语句来确保线程安全。此外,还提到了其他同步工具如 `Monitor` 和 `Semaphore`,帮助开发者实现更高效的数据同步策略,以达到既保证数据一致性又维持良好性能的目标。
281 0
|
安全 Java C#
C#多线程详解
C#多线程详解
292 0