C#多线程编程技术——多线程操作(没看懂)

线程,有时被称为轻量进程(LightWeight Process,LWP),是程序执行流的最小单元。线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

一、进程与线程

进程(Process)和线程(Thread)是操作系统 的基本概念,但是它们比较抽象并且不容易掌握。可以将进程理解为程序在计算机上的一次执行活动,而线程则是进程的一个实体。执行线程就体现程序的真实执行情况。

进程的概念

1、进程

进程是程序在计算机上的一次执行活动。运行一个程序就相当于启动一个进程。Windows系统利用进程把工作划分为多个独立的区域,每个应用程序实例对应一个进程。每个进程所占用的资源都是互相独立的。

进程资源包括:

(1)一个进程堆;

(2)一个或多个线程;

(3)一个虚拟地址空间,该空间独立于其它进程的地址空间;

(4)一个或多个代码段,包括.dll中的代码;

(5)一个或多个包含全局变量的数据段;

(6)环境字符串,包括环境变量信息;

(7)其他资源,例如打开的句柄、其它的堆等。

2、多进程

多进程就是在同一计算机系统 中,同一个时刻允许两个或两个以上的进程处于运行状态。多进程具有以下特点:

(1)进程间互相独立,可靠性高。

(2)进程之间不共享数据,没有锁问题,结构简单。

(3)需要跨进程边界,多进程调度开销较大。

线程的概念

1、线程

线程是程序中的一个执行流,每个线程都有自己的专用寄存器(栈、指针、程序计数器等),但代码区是共享的,即不同的线程可以执行同样的函数。

注意:一个进程可以有多个线程,一个线程必须有一个父进程,一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

2、多线程

多线程是指程序中包含多个执行流,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

(1)多线程具有以下优点。

可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其他的线程而不是等待,这样就大大提高了程序的效率。

(2)多线程具有以下缺点。

        ① 线程也是程序,所有线程需要占用内存,线程越多占用内存也越多;

        ② 多程序需要协调和管理,所以需要CPU时间跟踪线程;

        ③ 线程之间对共享资源的访问会相互影响,必须 解决竞用共享资源的问题

        ④ 线程太多会导致控制太复杂,最后可能造成很多Bug。

3、线程的生命周期

线程生命周期开始于System.Threading.Thread类的对象被创建时,结束于线程被终止或完成执行时。

下面列出了线程生命周期中的各种状态

(1)未启动状态:当线程实例被创建,但Start方法未被调用时的状况。

(2)就绪状态:当线程准备好运行并等待CPU周期时的状况。

(3)不可运行状态:已经调用Sleep方法、Wait方法或者通过I/O操作阻塞时,线程是不可运行的。

(4)死亡状态:当线程已完成执行或已中止时的状况。

在C#中,Thread类用于线程的工作。它允许创建并访问多线程应用程序 中的单个线程。进程中第一个被执行的线程称为主线程。

编写程序,获取当前的主线程,并为其命名。

可以通过Thread类的静态属性CurrentThread获取当前执行的线程,然后通过Name属性赋值”MainThread“。

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Thread th=Thread.CurrentThread;
            th.Name = "MainThread";
            Console.WriteLine("This is { 0 }", th.Name);
            Console.ReadLine();
        }
    }
}

 完整代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Thread th=Thread.CurrentThread;
            th.Name = "MainThread";
            Console.WriteLine("This is {0}", th.Name);
            Console.ReadLine();
        }
    }
}

运行结果:

Thread类

在.NET Framework中,所有与多线程机制应用相关的类都是放在System.Threading命名空间中的。

Thread类的属性及说明
属性说明
CurrentContext获取线程正在其中执行的当前上下文
CurrentCulture获取或设置当前线程的区域性
CurrentPrinciple获取或设置线程的当前负责人(对基于角色的安全性而言)
CurrentThread获取当前正在运行的线程
CurrentUICulture获取或设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
ExecutionContext获取一个ExecutionContext对象,该对象包含有关当前线程的各种上下文的信息
IsAlive获取一个值,该值指示当前线程的执行状态
IsBackground获取或设置一个值,该值指示某个线程是否为后台线程
IsThreadPoolThread获取一个值,该值指示线程是否属于托管线程池
ManagedThreadId获取当前托管线程的唯一标识符
Name获取或设置线程的名称
Priority获取或设置一个值,该值指示线程的高度优先级
ThreadState获取一个值,该值包含当前线程的状态

Thread类的方法及说明
方法说明
Abort在调用此方法的线程上引发ThreadAboutException,以开始终止此线程的过程。调用此方法通常会终止线程
GetApartmentState返回表示单元状态的ApartmentState值
GetDomain返回当前线程正在其中运行的当前域
GetDomainID返回唯一的应用程序域标识符
Interrupt中断处于WaitSleepJoin线程状态的线程
Join在此实例表示的线程终止前,阻止调用线程
ResetAbort取消当前线程所请求的Abort(Object)
SetApartmentState在线程启动前设置其单元状态
Sleep将当前线程挂起指定的时间
SpinWait导致线程等待由iterations参数定义的时间量
Start使线程得以按计划执行
Suspend挂起线程,或者如何线程已挂起,则不起作用
VolatileRead读取字段值。无论处理器的数目或处理器缓存的状态如何,该值都是由计算机的任何处理器写入的最新值
VolatileWrite立即向字段写入一个值,以使该值对计算机中的所有处理器都可见

二、线程的基本操作

通过使用Thread类,可以对线程进行创建、休眠、挂起、恢复、终止及设置优先权等操作。

创建线程

在C#中创建线程时,首先需要创建一个ThreadStart委托实例,再以这个ThreadStart委托作为参数,来构造Thread实例。

注意:Thread类拥有四种重载的构造函数,常用的一个函数接收一个ThreadStart类型的参数,而ThreadStart是一个委托,其语法格式如下:

public delegate void ThreadStart()

编写程序,启动创建好的线程

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        //创建线程的方法,输出0至10
        public static void ThreadMethod()
        {
            Console.WriteLine("辅助线程开始...");
            for(int i = 0; i < 10; i++)
            {
                Console.WriteLine("辅助线程:{0}", i);
                Thread.Sleep(2000);                         //调用Sleep方法,使辅助线程休眠2秒
            }
            Console.WriteLine("辅助线程结束.");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("主线程开始");
            //创建委托实例
            ThreadStart ts = new ThreadStart(ThreadMethod); //注册ThreadMethod方法
            //通过委托实例来构造Thread类
            Thread th = new Thread(ts);
            th.Start();                                     //启动线程
            for(char i='A';i<'K'; i++)
            {
                Console.WriteLine("主线程:{0}", i);
                Thread.Sleep(1000);                         //调用Sleep方法,使主线程休眠1秒
            }
            th.Join();                                      //主线程等待辅助线程结束 
            Console.WriteLine("主线程结束");
            Console.ReadLine();
        }
    }
}

运行结果:

 在代码中,首先用户可以自定义一个静态的void方法ThreadMethod;然后在Main方法中,创建ThreadStart委托的实例ts;接着通过ts构造Thread类的实例th,这样就创建好一个线程。由于Main方法是程序的入口点,优先执行Main方法,所以Main方法是主线程,ThreadMethod方法是辅助线程;执着调用Start方法启动线程,此时主线程中的for循环执行每一次后就会休息1秒,而辅助线程每执行一次则休眠2秒;最后调用了Join方法,在辅助线程中的for循环执行完之后 停止执行主线程中的for循环。

读了代码不是很明白。

线程休眠

线程的休眠是通过Thread类的Sleep方法实现的,而Thread类的实例的IsAlive属性可以判断线程是否执行完毕。

Sleep方法有以下两种重载形式。

(1)将当前线程挂起指定的毫秒数,语法格式如下:

public static void Sleep (int millisecondsTimeout)

millisecondsTimeout:线程被阻止的毫秒数。如果该参数的值为零,则该线程会将其时间的剩余部分让给任何已经准备好运行的、具有同等优先级的线程,否则会无限制阻止线程。

(2)将当前线程挂起指定的时间,语法格式如下:

public static void Sleep (TimeSpan timeout)

timeout:线程被阻止的时间量的TimeSpan。

编写程序,创建线程,并在运行时休眠5秒。

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        public static void Method()
        {
            Console.WriteLine("启动线程");
            //线程暂停5000毫秒
            int t = 5000;
            Console.WriteLine("线程暂停 {0} 秒",t / 1000);
            Thread.Sleep(t);
            Console.WriteLine("线程恢复");
        }
        static void Main(string[] args)
        {
            ThreadStart ts = new ThreadStart(Method);
            Thread th = new Thread(ts);     //创建线程
            th.Start();                     //启动线程
            Console.ReadLine();
        }
    }
}

运行结果:

线程的挂起与恢复

Suspend方法用于挂起线程,Resume方法用于继续执行已经挂起的线程。可以使用这两个方法进行线程的同步,和Start方法有些类似的是,在调用Suspend方法后不会立即停止,而是执行到一个安全点后挂起。

1、Suspend方法

挂起线程,或者如果线程已挂起,则不起作用,语法格式如下:

public void Suspend();

2、Rusume方法

继续已挂起的线程,语法格式如下:

public void Resume();

编写程序,自定义两个线程,主线程(MainThread方法)和工作线程(WorkThread方法),主线程倒序输出,工作线程正序输出。先完成主线程,再完成工作线程。

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ThreadStart work = new ThreadStart(WorkThread);    //创建工作线程
            Thread th = new Thread(work);
            th.Start();        //启动线程
            th.Suspend();        //挂起线程
            MainThread();        //主线程
            th.Resume();           //恢复线程
            Console.ReadLine();
        }
        static void WorkThread()
        {
            for (long i = 1; i < 1000000000; i++)
            {
                if (i % 100000000 == 0 && i != 0)
                {
                    Console.WriteLine("工作线程WorkThread-->i={0}", i);
                }
            }
        }
        static void MainThread()
        {
            long gap = 0;
            for (long i = 1000000000; i >= 0; i--)
            {
                gap = i - 1;
                if (i % 100000000 == 0)
                {
                    Console.WriteLine("主线程MainThread-->i={0}", i);
                }
            }
            Console.WriteLine();
        }
    }
}

运行如下 :与书上不一致。

主线程MainThread-->i=1000000000
主线程MainThread-->i=900000000
主线程MainThread-->i=800000000
主线程MainThread-->i=700000000
主线程MainThread-->i=600000000
主线程MainThread-->i=500000000
主线程MainThread-->i=400000000
主线程MainThread-->i=300000000
主线程MainThread-->i=200000000
主线程MainThread-->i=100000000
主线程MainThread-->i=0

工作线程WorkThread-->i=100000000
工作线程WorkThread-->i=200000000
工作线程WorkThread-->i=300000000
工作线程WorkThread-->i=400000000
工作线程WorkThread-->i=500000000
工作线程WorkThread-->i=600000000
工作线程WorkThread-->i=700000000
工作线程WorkThread-->i=800000000
工作线程WorkThread-->i=900000000

在代码中,用户定义了两个方法WorkThread和MainThread。MainThread方法用于倒序输出 0~10;WorkThread方法用于正序输出 1~9;然后在Main方法中,创建ThreadStart委托的实例work;接着通过work构造Thread类的实例th,这样就创建好一个线程;最后通过start方法,启动线程。

挂起线程使用Suspend方法。线程被挂起后,操作被停止或进入休眠状态。因此,从结果中可以看出,此时主线程正常执行,但是工作线程WorkThread没有被执行。那么要想工作线程能继续执行,就需要使用Resume方法恢复线程。

终止线程

线程的终止是通过Thread类的Abort方法和Join方法来实现。

1、Abort方法

当一个线程执行时间太长时,用户有可能要终止这个线程,这就要使用Abort方法。该方法有两种重载方式:

public void About()        //终止进程

public void About(0bject StateInfo)        //终止线程并提供有关线程终止的异常信息

参数stateInfo是一个对象,包含应用程序特定的信息(如状态),该信息可供正被终止的线程使用。

注意:在线程调用Abort方法时,会引发ThreadAbortException异常。如果没有捕获异常,线程将会终止通过。

编写程序,启动线程,while循环5次后终止线程。

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ThreadStart work = new ThreadStart(WorkThread);     //创建工作线程
            Thread th = new Thread(work);
            th.Start();
            int i = 0;
            while(th.IsAlive)
            {
                i++;
                Thread.Sleep(500);
                if(i==5)
                {
                    th.Abort();
                    Console.WriteLine("\r\n线程被终止");
                }
            }
            Console.ReadLine();
        }
        static void WorkThread()
        {
            for (long i = 1; i < 1000000000; i++)
            {
                if (i % 100000000 == 0 && i != 0)
                {
                    Console.WriteLine("工作线程WorkThread-->i={0}", i);
                }
            }
        }
    }
}

运行结果如下:与书上不一样。

 在代码中,用户首先自定义方法WorkThread,用于输出一组数据;然后在Main方法中,创建ThreadStart委托的实例work;接着通过work构造Thread类的实例th,这样就创建好一个线程;最后通过start方法,启动工作线程。

中止线程使用Abort方法。线程被中止,就停止运行,是无法恢复的,因为Windows会永久地删除被中止线程的所有数据。跟挂起工作线程时的结果一样,中止工作线程后,工作线程自然不会被执行。

2、Join方法

Join方法用于等待线程中止,如果后续的处理依赖于另一个已经终止的线程,可以调用Join方法,等待线程中止。该方法有三种重载形式:

public void Join()

public bool Join(int millisecondsTimeout)

public bool Join(TimeSpan timeout)

参数说明:

millsecondsTimeout表示等待线程终止的毫秒数。如果线程已终止,则返回值为true,如果线程经过了millisecondsTimeout指定时间后未终止,返回值为false。

timeout表示等待线程终止的时间量TimeSpan。如果线程已终止,则返回值为true,如果线程经过timeout时间量之后未终止,则返回值为false。

编写程序,使用Join方法等待线程终止。

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ThreadStart work = new ThreadStart(WorkThread);     //创建工作线程
            Thread th = new Thread(work);
            th.Start();             //启动线程
            th.Join();          //等待工作线程中止
            MainThread();
            Console.ReadLine();
        }
        static void WorkThread()
        {
            for (long i = 1; i < 1000000000; i++)
            {
                if (i % 100000000 == 0 && i != 0)
                {
                    Console.WriteLine("工作线程WorkThread-->i={0}", i);
                }
            }
            Console.WriteLine("工作线程执行完毕");
        }
        static void MainThread()
        {
            long gap = 0;
            for (long i = 1000000000; i >= 0; i--)
            {
                gap = i - 1;
                if (i % 100000000 == 0)
                {
                    Console.WriteLine("主线程MainThread-->i={0}", i);
                }
            }
            Console.WriteLine("主线程执行完毕");
        }
    }
}

运行结果如下:

工作线程WorkThread-->i=100000000
工作线程WorkThread-->i=200000000
工作线程WorkThread-->i=300000000
工作线程WorkThread-->i=400000000
工作线程WorkThread-->i=500000000
工作线程WorkThread-->i=600000000
工作线程WorkThread-->i=700000000
工作线程WorkThread-->i=800000000
工作线程WorkThread-->i=900000000
工作线程执行完毕
主线程MainThread-->i=1000000000
主线程MainThread-->i=900000000
主线程MainThread-->i=800000000
主线程MainThread-->i=700000000
主线程MainThread-->i=600000000
主线程MainThread-->i=500000000
主线程MainThread-->i=400000000
主线程MainThread-->i=300000000
主线程MainThread-->i=200000000
主线程MainThread-->i=100000000
主线程MainThread-->i=0
主线程执行完毕

代码如下:

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

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            ThreadStart work = new ThreadStart(WorkThread);     //创建工作线程
            Thread th = new Thread(work);
            th.Start();             //启动线程
            th.Join(1000);          //等待工作线程中止
            MainThread();
            Console.ReadLine();
        }
        static void WorkThread()
        {
            for (long i = 1; i < 1000000000; i++)
            {
                if (i % 1000000000 == 0 && i != 0)
                {
                    Console.WriteLine("工作线程WorkThread-->i={0}", i);
                }
            }
            Console.WriteLine("工作线程执行完毕");
        }
        static void MainThread()
        {
            long gap = 0;
            for (long i = 1000000000; i >= 0; i--)
            {
                gap = i - 1;
                if (i % 100000000 == 0)
                {
                    Console.WriteLine("主线程MainThread-->i={0}", i);
                }
            }
            Console.WriteLine("主线程执行完毕");
        }
    }
}

运行结果如下: 

主线程MainThread-->i=1000000000
工作线程WorkThread-->i=100000000
主线程MainThread-->i=900000000
工作线程WorkThread-->i=200000000
主线程MainThread-->i=800000000
工作线程WorkThread-->i=300000000
主线程MainThread-->i=700000000
工作线程WorkThread-->i=400000000
工作线程WorkThread-->i=500000000
主线程MainThread-->i=600000000
工作线程WorkThread-->i=600000000
主线程MainThread-->i=500000000
工作线程WorkThread-->i=700000000
主线程MainThread-->i=400000000
工作线程WorkThread-->i=800000000
主线程MainThread-->i=300000000
工作线程WorkThread-->i=900000000
主线程MainThread-->i=200000000
工作线程执行完毕
主线程MainThread-->i=100000000
主线程MainThread-->i=0
主线程执行完毕

 

主线程MainThread-->i=1000000000
工作线程WorkThread-->i=100000000
主线程MainThread-->i=900000000
工作线程WorkThread-->i=200000000
主线程MainThread-->i=800000000
工作线程WorkThread-->i=300000000
主线程MainThread-->i=700000000
工作线程WorkThread-->i=400000000
工作线程WorkThread-->i=500000000
主线程MainThread-->i=600000000
工作线程WorkThread-->i=600000000
主线程MainThread-->i=500000000
工作线程WorkThread-->i=700000000
主线程MainThread-->i=400000000
工作线程WorkThread-->i=800000000
主线程MainThread-->i=300000000
工作线程WorkThread-->i=900000000
工作线程执行完毕
主线程MainThread-->i=200000000
主线程MainThread-->i=100000000
主线程MainThread-->i=0
主线程执行完毕

线程的优先级

线程的优先级可以通过Thread类的Priority属性设置,Priority属性是一个ThreadPriority型枚举,列举了5个优先等级:AboveNormal、BelowNormal、Highest、Lowest、Normal。

普通线程的优先级默认为Normal;如果想有更高的优先级,可设置为AboveNormal或Highest;如果想有较低的优先级,可设置为BelowNormal或Lowest。线程优先级值,从高到低按顺序如下表格。

线程的优先级值及说明
优先级值说明
Highest在具有任何其他优先级的线程之前
AboveNormal可以将Thread安排在具有Highest优先级线程之后,在Normal之前
Normal在AboveNormal之后,BelowNormal之前。默认值。
BelowNormal在Normal之后,Lowest之前
Lowest在具有其他任何优先级的线程之后

可以通过调用线程的Priority属性来获取和设置其优先级。Priority属性用来获取或设置一个值 ,该值指示线程的调度优先级。

语法格式如下:

public ThreadPriority Priority(get;set;)

属性值是ThreadPriority枚举值之一,默认值为Normal。

编写程序,分别创建两个线程,然后通过设定不同的优先级来显示线程的名称和优先级。

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

namespace ConsoleApp1
{
    internal class Program
    {
        public static void method()
        {
            //输出线程的名称
            Console.WriteLine("线程名称:{0}", Thread.CurrentThread.Name.ToString());
            //输出线程的优先级
            Console.WriteLine("线程的优先级:{0}",Thread.CurrentThread.Priority.ToString());
        }
        static void Main(string[] args)
        {
            ThreadStart ts1 = new ThreadStart(method);
            ThreadStart ts2 = new ThreadStart(method);
            Thread t1=new Thread(ts1);
            Thread t2 = new Thread(ts2);
            //为两个线程命名
            t1.Name = "学习C#线程一";
            t2.Name = "学习Java线程二";
            //指定线程t1的优先级为Highest
            t1.Priority = ThreadPriority.Highest;
            //启动两个线程
            t1.Start();
            t2.Start();
            Console.ReadLine();
        }
    }
}

运行结果如下:

线程的实现

使用Thread类创建线程

Thread类位于System.Threading命名空间下,该类主要用于创建并控制线程、设置线程优先级并获取其状态。

创建线程需要使用Thread类的构造函数,语法如下:

public Thread(ThreadStart start)
public Thread(ParameterizedThreadStart start)

Thread类的常用属性及说明
属性说明
ApartmentState获取或设置此线程的单元状态
CurrentContext获取线程正在其中执行的当前上下文
CurrentThread获取当前正在运行的线程
IsAlive获取一个值,该值指示当前线程的执行状态
ManagedThreadId获取当前托管线程的唯一标识符
Name获取或设置线程的名称
Priority获取或设置一个值,该值指示线程的调度优先级
ThreadState获取一个值,该值包含当前线程的状态

创建了Thread类的对象之后,线程对象已存在并已配置,但并未创建实际的线程,这时只有在调用Start方法后,才会创建实际的线程。

创建一个Windows窗体应用程序,实现图标移动的功能。具体实现时,在窗体中添加一个PictureBox控件,并设置相应的C#图标,然后使用Thread线程控制 该控制 的坐标位置,从而实现移动图标的效果。

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;       //使线程可以调用窗体控件
        }
        int x = 12;
        void Rool()
        {
            while (x <= 260)        //设置循环条件
            {
                pictureBox1.Location = new Point(x, 12);
                Thread.Sleep(500);  //使线程休眠500毫秒
                x += 4;        //使横坐标每次增加4
                if (x >= 260)
                {
                    x = 12;     //当图标到达标签的最右边时,使其回到标签最左边。
                }
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            Thread th = new Thread(new ThreadStart(Rool));      //创建线程对象
            th.Start();     //启动线程
        }
    }
}

线程的休眠

线程的休眠主要通过Thread类的Sleep方法实现,该方法用来将当前线程阻塞指定的时间,它有两个重载形式。

(1)将当前线程挂起指定的时间,语法如下:

public static void Sleep(int millisecondsTimeout)

参数millisecondsTimeout表示线程被阻塞的毫秒数。指定1以使其他可能正在等待的线程能够执行;指定Timeout.Infinite以无限期阻塞线程。

(2)将当前线程阻塞指定的时间,语法如下:

参数timeout表示线程被阻塞的时间量的TimeSpan。指定持续时间为1毫秒,可以使其他可能正在等待的线程能够执行;指定持续时间为-1毫秒,可以无限期阻塞线程。

下面代码用来使当前线程休眠一秒钟,代码如下:

Thread.Sleep(1000);

模拟红绿灯变化场景,红灯亮8秒,绿灯亮5秒,黄灯亮2秒。主要代码如下:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        CheckForIllegalCrossThreadCalls = false;
    }

    void ControlLight()
    {
        while (true)
        {
            Thread.Sleep(5000);
            pictureBox1.Image = Image.FromFile("Yellow.png");
            Thread.Sleep(2000);
            pictureBox1.Image = Image.FromFile("Red.png");
            Thread.Sleep(8000);
            pictureBox1.Image = Image.FromFile("Green.png");
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Thread th = new Thread(new ThreadStart(ControlLight));
        th.Start();
    }
}

线程的加入

当某个线程使用Join()方法加入到另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行。

Join()方法用来阻塞调用线程,直到某个线程终止时为止,它有3种重载形式:

(1):在继续执行标准的COM和SendMessage消息处理期间,阻塞调用线程,直到某个线程终止为止,语法如下:

public void Join()

(2):在继续执行标准的COM和SendMessage消息处理期间,阻塞调用线程,直到某个线程终止或经过了指定时间为止。语法如下:

public bool Join(int millisecondsTimeout)

millisecondsTimeout:等待线程终止的毫秒数。

返回值 :如果线程已终止,则为true;如果线程在经过了millisendsTimeout参数指定的时间后未终止,则为false。

(3):在继续执行标准的COM和Sendmessage消息处理期间,阻塞调用线程,直到某个线程终止或经过了指定时间为止。语法如下:

public bool Join(TimeSpan timeout)

timeout:等待线程终止的时间量的TimeSpan。

返回值:如果线程已终止,则为true;如果线程在经过了timeout参数指定的时间量后未终止,则为false。

创建一个Windows窗体应用程序,默认窗体中包括两个进度条,进度条的进度由线程来控制,通过使用Join方法使上面的进度条必须等待下面的进度条完成后才可以继续。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        CheckForIllegalCrossThreadCalls = false;
    }
    Thread th1, th2;
    void Pro1()
    {
        int count = 0;
        while (true)
        {
            progressBar1.PerformStep();
            count += progressBar1.Step;
            Thread.Sleep(100);
            if (count == 20)
            {
                th2.Join();
            }
        }
    }
    void Pro2()
    {
        int count = 0;
        while (true)
        {
            progressBar2.PerformStep();
            count += progressBar2.Step;
            Thread.Sleep(100);
            if (count == 100)
            {
                break;
            }
        }
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        th1 = new Thread(new ThreadStart(Pro1));
        th1.Start();
        th2 = new Thread(new ThreadStart(Pro2));
        th2.Start();
    }
}

线程的终止

终止线程使用Thread类的Abort方法实现,该方法有两个重载形式。

(1)终止线程,在调用此方法的线程上引发ThreadAbortException异常,以开始终止此线程的过程。语法如下:

public void Abort()

(2)终止线程,在调用此方法的线程上引发ThreadAbortException异常,以开始终止此线程并提供有关线程终止的异常信息的过程。语法如下:

public void Abort(Object stateInfo)

参数stateInfo是一个Object对象,它包含应用程序特定的信息(如状态),该信息可供正被终止的线程使用。

线程的优先级

线程的优先级值及说明
优先级值说明
AboveNormal可以将Thread安排在具有Highest优先级的线程之后,在具有Normal优先级的线程之前
BelowNormal可以将Thread安排在具有Normal优先级的线程之后,在具有Lowest优先级的线程之前
Highest可以将Thread安排在具有任何其他优先级的线程之前
Lowest可以将Thread安排在具有任何其他优先级的线程之后
Normal可以将Thread安排在具有AboveNormal优先级的线程之后,在具有BelowLowest优先级的线程之前。默认情况下,线程具有Normal优先级

Priority属性用来获取或设置一个值,该值指示线程的调度优先级,其语法如下:

public ThreadPriority Priority { get; set; }

属性值为ThreadPriority枚举值之一。默认值 为Normal。

线程同步机制

使用lock关键字实现线程同步

使用Monitor类实现线程同步

使用Mutex类实现线程同步

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值