您的位置:首页 > 编程语言 > C#

[C#基础]线程学习笔记(二)

2015-06-03 08:06 716 查看
参考链接:
http://blog.csdn.net/jasonvip_c/article/details/5718636 http://www.cnblogs.com/miniwiki/archive/2010/06/18/1760540.html
1.前台线程与后台线程

Net的公用语言运行时(Common Language Runtime,CLR)能区分两种不同类型的线程:前台线程和后台线程。这两者的区别就是:应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。

一个线程是前台线程还是后台线程可由它的IsBackground属性来决定。这个属性是可读又可写的。它的默认值为false,即意味着一个线程默认为前台线程。我们可以将它的IsBackground属性设置为true,从而使之成为一个后台线程。

示例:

using System;
using System.Threading;

class ThreadTest11
{
    static void Main(string[] args)
    {
        for (int i = 0; i < 10; i++)
        {
            Thread t = new Thread(Go);
            //若添加这句话,则创建完十个线程之后就会退出控制台程序
            //若注释这句话,则等待五秒后就会退出控制台程序
            //t.IsBackground = true;
            t.Start();
        } 
    }

    static void Go()
    {
        DateTime start = DateTime.Now;
        while ((DateTime.Now - start).Seconds < 5) ;
    }
}


既然前台线程和后台线程有这种差别,那么我们怎么知道该如何设置一个线程的IsBackground属性呢?下面是一些基本的原则:对于一些在后台运行的线程,当程序结束时这些线程没有必要继续运行了,那么这些线程就应该设置为后台线程。比如一个程序启动了一个进行大量运算的线程,可是只要程序一旦结束,那个线程就失去了继续存在的意义,那么那个线程就该是作为后台线程的。而对于一些服务于用户界面的线程往往是要设置为前台线程的,因为即使程序的主线程结束了,其他的用户界面的线程很可能要继续存在来显示相关的信息,所以不能立即终止它们。这里我只是给出了一些原则,具体到实际的运用往往需要编程者的进一步仔细斟酌。

2.线程与进程

一个不错的解释:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html

简单地说,就是:

一个系统可以执行多个进程,允许多个任务同时运行

一个进程可以执行多个线程,允许任务分成不同的部分运行

一个进程的内存空间是共享的,每个线程都可以使用这些共享内存

3.何时使用多线程

多线程程序一般被用来在后台执行耗时的任务。主线程保持运行,并且工作线程做它的后台工作。对于Windows Forms程序来说,如果主线程试图执行冗长的操作,键盘和鼠标的操作会变的迟钝,程序也会失去响应。由于这个原因,应该在工作线程中运行一个耗时任务时添加一个工作线程,即使在主线程上有一个有好的提示“处理中...”,以防止工作无法继续。这就避免了程序出现由操作系统提示的“没有相应”,来诱使用户强制结束程序的进程而导致错误。

4.何时不使用多线程

多线程也同样会带来缺点,最大的问题是它使程序变的过于复杂,拥有多线程本身并不复杂,复杂是的线程的交互作用,这带来了无论是否交互是否是有意的,都会带来较长的开发周期,以及带来间歇性和非重复性的bugs。因此,要么多线程的交互设计简单一些,要么就根本不使用多线程。除非你有强烈的重写和调试欲望。
当用户频繁地分配和切换线程时,多线程会带来增加资源和CPU的开销。

5.线程优先级

public enum ThreadPriority

有五种取值,按优先级从高到低为:

Highest > AboveNormal > Normal Below > Normal > Lowest

默认情况下,线程具有Normal 优先级。

using System;
using System.Threading;

class ThreadTest12
{
    static void Main()
    {
        PriorityTest priorityTest = new PriorityTest();
        ThreadStart startDelegate = new ThreadStart(priorityTest.ThreadMethod);

        Thread threadOne = new Thread(startDelegate);
        threadOne.Name = "ThreadOne";
        Thread threadTwo = new Thread(startDelegate);
        threadTwo.Name = "ThreadTwo";

        threadTwo.Priority = ThreadPriority.BelowNormal;
        threadOne.Start();
        threadTwo.Start();

        // Allow counting for 3 seconds.
        Thread.Sleep(3000);
        priorityTest.LoopSwitch = false;
        Console.Read();
    }
}

class PriorityTest
{
    bool loopSwitch;

    public PriorityTest()
    {
        loopSwitch = true;
    }

    public bool LoopSwitch
    {
        set { loopSwitch = value; }
    }

    public void ThreadMethod()
    {
        long threadCount = 0;

        while (loopSwitch)
        {
            threadCount++;
        }
        Console.WriteLine("{0} with {1,11} priority " +
            "has a count = {2,13}", Thread.CurrentThread.Name,
            Thread.CurrentThread.Priority.ToString(),
            threadCount.ToString("N0"));
    }
}


运行结果:



6.异常处理

using System;
using System.Threading;

class ThreadTest13
{
    static void Main(string[] args)
    {
        try 
        { 
            new Thread(Go).Start();
        }
        catch (Exception ex) 
        { 
            Console.WriteLine("Exception");
        }
    }

    static void Go()
    {
        throw null;
    }
}


这里try/catch语句一点用也没有,新创建的线程会引发NullReferenceException异常

正确的捕获异常的方法是:

using System;
using System.Threading;

class ThreadTest13
{
    static void Main(string[] args)
    {
        new Thread(Go).Start();
    }

    static void Go()
    {
        try
        {
            throw null;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception");
            Console.Read();
        }
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: