C#线程处理

  C#支持通过多线程并行地执行代码,一个线程有它独立的执行路径,能够与其它的线程同时地运行。一个C#程序开始于一个单线程,这个单线程是被CLR和操作系统(也称为“主线程”)自动创建的,并具有多线程创建额外的线程。
  除非被指定,否则所有的例子都假定以下命名空间被引用了:

using System;
using System.Threading;

C#开启线程的方法有:

  • 异步委托
  • 通过Thread类
  • 线程池
  • 任务

  总的来说其实线程的开启基本都涉及到委托的使用。

一、异步委托开启线程

首先来看一个比较简单的例子,采用第一种开启线程的方法——异步委托

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("TestThread");
        }
        static void Main(string[] args)
        {
            Action a = test;
            a.BeginInvoke(null, null);
            Console.WriteLine("MainThread");
            Console.ReadLine();
        }
    }
}

  编译运行,发现结果与预期有所不同。结果如下图
Thread
  如果按着逐行运行代码的方式,那么应该是先输出TestThread,但是结果却是先输出MainThread。
  将a.BeginInvoke(null,null);Console.WriteLine("MainThread");对调位置之后,结果和之前的依然一致。这就说明,异步委托开启的线程是和主线程同时同步进行的。
  Action委托是指向一个没有返回值的函数,那么假设一个线程,我们需要取得他的返回结果并输出,那么就要用到Func委托。
  看下面的源码

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static string test(int i, string str)
        {
            Console.WriteLine("TestThread" + "\t参数i是:" + i);
            return str;
        }
        static void Main(string[] args)
        {
            Func<int, string, string> a = test;
            IAsyncResult res = a.BeginInvoke(1, "返回值", null, null);
            string o = a.EndInvoke(res);
            Console.WriteLine("MainThread\t" + "线程返回值是:" + o);
            Console.ReadLine();
        }
}

Thread
同时异步委托开启线程中,判断线程是否结束的方法也有两种,一种是利用IAsyncResult的IsCompleted方法,一种是使用方法进行线程结束判断。
  具体使用方法如下。

  1. IsCompleted(bool)
IAsyncResult ia = a.BeginInvoke()
if(ia.IsCompleted == false)
{
    //GoOn
}
  1. AsyncWaitHandle
IAsyncResult ia = a.BeginInvoke()
ia.AsyncWaitHandle.WaitOne(Time);//Time为等待时间,超时后才会运行下一行代码,未完成直接跳出返回false

  或者通过自定义方法,BeginInvoke中倒数第二个参数是一个委托,传递一个函数,在线程结束之后会自动的调用。

static string Test(int a)
{

}
Func<int, string> a = Test;
IAsyncResult ia = a.BeginInvoke(100, CallBack, a);
static void CallBack(IAsyncResult ar)
{
    Func<int, string> a = ia.AsyncState as Func<int, string>;
    string res = a.EndInvoke(ar);
}

  在使用Lambda表达式作为委托的时候,最后一个参数可以为空,因为Lambda表达式可以访问外部变量。

二、使用Thread类开启线程

  使用Thread类创建一个实例,它的构造方法中需要传递一个委托。通过委托绑定线程。
  直接上代码

using System;
using System.Threading;

namespace Study
{
    class Program
    {
        static void test()
        {
            Console.WriteLine("Thread");
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");
        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start();
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

Thread
  对于需要传递参数的委托,则必须制定参数类型为object,在线程Start方法中传递参数

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id + ",\t参数是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Thread t = new Thread(test);
            t.Start("xxx.avi");
            Console.WriteLine("Main");
            Console.Read();
        }
    }
}

Thread
  当然你也可以自定义一个类,在类中自定义数据传递。

三、线程池

  这种方法有助于节省时间,具体使用方法如下

using System;
using System.Threading;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id + ",\t参数是:" + c);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(test, "asfasf");
            Console.Read();
        }
    }
}

  其中委托必须要有一个参数,无论是否使用该参数。且只适用于使用时间短的线程,不能改变优先级

四、任务

  使用Task类开启线程,还有TaskFactory创建
  Task类实例

using System;
using System.Threading;
using System.Threading.Tasks;

namespace SummerStudy
{
    class Program
    {
        static void test(object c)
        {
            int id = Thread.CurrentThread.ManagedThreadId;
            Console.WriteLine("Thread,\t线程id为" + id);
            Thread.Sleep(2000);
            Console.WriteLine("TimeOver");

        }
        static void Main(string[] args)
        {
            Task t = new Task(test, "Asfgasg");
            t.Start();

            //或者

            TaskFactory tf = new TaskFactory();

            Task t1 = tf.StartNew(test);
            Console.Read();
        }
    }
}





作  者:WarrenRyan
出  处:https://www.cnblogs.com/WarrenRyan/
关于作者:热爱数学、热爱机器学习,喜欢弹钢琴的不知名小菜鸡。
版权声明:本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。若需商用,则必须联系作者获得授权。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!


博主一些其他平台:
微信公众号:寤言不寐
BiBili——小陈的学习记录
Github——StevenEco
BiBili——记录学习的小陈(计算机考研纪实)
掘金——小陈的学习记录
知乎——小陈的学习记录

联系方式:

电子邮件:cxtionch@live.com

社交媒体联系二维码:

posted @ 2019-02-18 23:47  WarrenRyan  阅读(1700)  评论(1编辑  收藏  举报