c# 线程

简介:这一篇我们主要学习线程及相关示例。

 

C# Threading

何谓线程,即并行工作或代码执行。为了同步执行多任务则意味着threading。

例如在电脑桌面,开启微软的PPT和Excel就是线程。一个程序经常会以两种方式被执行:同步或异步的方式。

同步则意味者多个工作是一个接一个的被执行。下图的work 2就必须等到work 1完成后才能开始。

 

 

 

 

 

 

 

 

 

异步则可以在同一时间执行多个工作。

MSexcel跟PPT的异步执行是一个最常见的线程示例。系统为每一个开启的应用程序生成了对应的新线程,因此每一个线程有一个独立的执行通道去异步执行对应的应用。

C#在Console Application,WindowsForm,WPF中广泛支持线程threading,所以我们可以在一个console app里面创建新线程,这意味着我们可以创造一个多线程环境。

 

用示例手把手教你C#线程

这里使用VS2017,其它版本操作大致类似.

为了在工程中创建新线程,我们需要导入线程的命名空间System.Threading,这能帮助建立多线程应用。

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

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
        }
    }
}

如你所见,没有添加threading线程命名空间,便无法使用thread类。 添加后,便可正常运行。

现在为了更好的进一步理解,我们会新建两个方法,work1和work2 ,在各自内容中会添加一个for循环,然后可以观察各自的运行情况:

 class Program
    {
        static void Main(string[] args)
        {
            Work1();
            Work2();
            Console.ReadLine();
        }

        static void Work1()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Work 1 is called " + i.ToString());
            }
        }

        static void Work2()
        {
            for (int i = 1; i <= 10; i++)
            {
                Console.WriteLine("Work 2 is called " + i.ToString());
            }
        }
    }

如你所见,我们建了两个普通的功能函数,执行后下面是输出:

看完输出你会发现,当两个函数同步运行时(work2紧接着work1),work2必须等到work1的循环完成后才会开始运行。

但考虑到现代社会习惯的多任务同步执行,在实际运用中,我们需要另一种机制来同时执行work1和work2。因此我们把这种机制叫做Threading。

 

下面我们就会看到threading是如何解决两个功能函数同时运行的问题。

第一步

添加命名空间。

using System;
using System.Threading;

第二步

在main函数中创建线程对象。

static void Main(string[] args)
        {
            Thread oThreadone = new Thread(Work1);
            Thread oThreadtwo = new Thread(Work2);

            Console.ReadLine();
        }

第三步

调用线程对象。

static void Main(string[] args)
        {
            Thread oThreadone = new Thread(Work1);
            Thread oThreadtwo = new Thread(Work2);

            oThreadone.Start();
            oThreadtwo.Start();

            Console.ReadLine();
        }

调用成功后,我们来看一下输出:

可以看到work2是跟work1同时执行的。为了使得输出效果更明显,你可以在work1及work2中加一点延时,这样你可以看到每一次延时后,两个work同步输出的内容。

由上可证,我们可以采用异步的方法同时执行多个任务。

 

为了创建线程类的应用,还有一些常用且比较重要的方法。

  1. 1 : Thread Join
  2. 2 : Thread Sleep
  3. 3 : Thread Abort

Thread join的使用 

Thread.Join() 使线程完成工作或直到该线程完工后让另一线程停止。join方法使其可以附加到任意线程,它会先执行那个线程然后使其它停止。如果文字比较难懂,那么可以先看看join的示例把。

class Program
    {
        static void Main(string[] args)
        {

            Thread oThread = new Thread(MethodJoin);
            oThread.Start();
            oThread.Join();
            Console.WriteLine("work completed..!");
            Console.ReadLine();
        }

        static void MethodJoin()
        {
            for (int i = 0; i <= 10; i++)
            {
                Console.WriteLine("work is in progress..!");

            }

        }
    }

如你所见,这里我建了一个新的方法MethodJoin(),并用join将他附加到oThread上。

如图你可以看到MethodJoin里所有的内容都已执行完,然后才回到main中做剩下的工作。

 

Thread Sleep的使用

顾名思义,sleep可以使得线程延迟一个特定的时间。在sleep模式下,cpu不会消耗任何资源。

接下来的一个例子,我会使得一个线程停留4s,然后输出一些内容,总共6次。为了计算准确,这里加入了.net Diagnostics 命名空间,可以使用码表以及执行时间。

using System.Threading;
using System.Diagnostics;
using System;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stWatch = new Stopwatch();
        stWatch.Start();

        Thread oThread = new Thread(ProcessSleep);
        oThread.Start();
        oThread.Join();

        stWatch.Stop();
        TimeSpan ts = stWatch.Elapsed;

        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds);
        Console.WriteLine("TotalTime " + elapsedTime);

        Console.WriteLine("work completed..!");
        Console.ReadLine();
    }

    static void ProcessSleep()
    {
        for (int i = 0; i <= 5; i++)
        {
            Console.WriteLine("work is in progress..!");
            Thread.Sleep(4000); 
        }
    }
}

 如图,在ProcessSleep中加入了一个4s的延时,下面是输出的内容:

 

Thread Abort的使用

如名,abort就是结束或终止进程,在停止进程中,它会触发ThreadAbortException。

Thread objThread = new Thread(ProcessJoin);
objThread.Start();
objThread.Join();

objThread.Abort();

 

c#中 线程的类型

前台线程Foreground Thread

如你所知Main函数本身是一个独立线程,所以在main里面加入一个线程则意味者这将成为一个多线程应用。前端线程Foreground 可以一直执行完毕即使主线程终止。用例子来解释foregound的生命周期不依赖主线程:

class Program
    {
        static void Main(string[] args)
        {
            Thread oThread = new Thread(WorkThread);
            oThread.Start();
            Console.WriteLine("Main Thread Quits..!");
        }

        static void WorkThread()
        {
            for (int i = 0; i <= 4; i++)
            {
                Console.WriteLine("Worker Thread is in progress..!");
                Thread.Sleep(2000); 
            }
            Console.WriteLine("Worker Thread Quits..!");
        }
    }

 

从上图可以看出,即使main已经终止,workthread仍然持续在输出。

 

后台线程Background Thread

后台线程与前台线程的机制刚刚相反,即当主线程终止时,后台线程也终止。为了运行后台线程,我们需要将IsBackground的属性设置为true。

Thread oThread = new Thread(WorkThread);
oThread.IsBackground = true;
using System.Threading;
using System.Diagnostics;
using System;

class Program
{
    static void Main(string[] args)
    {
        Thread oThread = new Thread(WorkThread) { IsBackground = true };

        oThread.Start();

        Console.WriteLine("Main Thread Quits..!");
        
    }

    static void WorkThread()
    {
        for (int i = 0; i <= 4; i++)
        {
            Console.WriteLine("Worker Thread is in progress..!");
            Thread.Sleep(2000);
        }

        Console.WriteLine("Worker Thread Quits..!");
    }
}

执行后,会发现开始后很快程序便结束,没有执行workthread内的内容;而前台线程会执行完所有内容。

 

好了,线程的基本内容就这样了,如果想更深入的了解,就得靠动手了!

 

参考:

1, https://www.tutorialspoint.com/csharp/csharp_multithreading.htm

2, http://www.learncsharptutorial.com/threading-and-types-of-threading-stepbystep.php

 

posted @ 2018-06-06 14:00  Nengka  阅读(732)  评论(0编辑  收藏  举报