C#程序设计 c# programming 多线程 C#程序设计课程组
教学内容 线程概述 System.Threading 命名空间 线程的建立与启动 线程的优先级与锁技术
线程概述
什么是多线程? 与进程有什么关系? 一个进程可以包含若干个线程 进程:是应用程序的一个运行例程,是应用程序的一次动态执行过程。 线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。 与进程有什么关系? 一个进程可以包含若干个线程
线程简介 线程 1 线程 2 线程 3 程序 1 单独的执行路径 线程 1 多线程 线程 2 线程 3 程序 2
为什么需要线程? 在同一时间点执行各项进程 同时执行所有任务,时间更少,效率更高 操作系统允许计算机同时执行多项操作 一览无遗 编译程序 人 体 在同一时间点执行各项进程 编译程序 发送/接收邮件 打印文件 其他 读 ,写 血液循环 程序 (进程)
很多程序功能都需要多线程技术
在以下情况中可能要使用到多线程: 程序需要同时执行两个或多个任务 程序要等待某事件的发生,例如用户输入、文件操作、网络操作、搜索等 后台程序
线程简介 多线程:在同一时间执行多个任务的功能,称为多线程或自由线程。 多线程的优点:可以同时完成多个任务;可以使程序的响应速度更快;可以让占用大量处理时间的任务或当前没有进行处理的任务定期将处理时间让给别的任务; 多线程的缺点: 对资源的共享访问可能造成冲突(对共享资源的访问进行同步或控制) ;程序的整体运行速度减慢等等。
System.Threading 命名空间与 线程的生命周期
System.Threading 命名空间
System.Threading 命名空间 在.NET程序设计中,线程是使用Thread类(或Timer类(线程计数器)、ThreadPool类(线程池))来处理的,这些类在System.Threading命名空间中: using System.Threading; Thread类:(实现线程的主要方法)一个Thread实例管理一个线程,即执行序列。通过简单实例化一个Thread对象,就可以创建一个线程,然后通过Thread对象提供的方法对线程进行管理。 Timer类:适用于间隔性的完成任务。 ThreadPool类:适用于多个小的线程。
Thread 类的属性和方法 引用System.Threading 命名空间 只创建但不启动线程 线程实例名.Start(); Thread 线程实例名 = new Thread(new ThreadStart(方法名)); 运行在线程上的方法 只创建但不启动线程 线程实例名.Start();
Thread 类的属性和方法 方法 属性 CurrentThread 获取当前正在运行的线程 IsAlive 指示当前线程的执行状态 Name 获取或设置线程的名称 Priority 获取或设置线程的优先级 CurrentContext 获取线程其中执行的当前上下文 IsBackground 指示线程是否为后台线程 ThreadState 获取或设置线程的当前状态 方法 Sleep() 将当前线程阻塞指定的毫秒数 Abort() 终止线程 Join() 阻塞调用线程,直到某个线程终止时为止 Resume() 继续已挂起的线程 Start() 启动线程 Suspend() 挂起线程 GetDomain 返回当前线程正在其中运行的当前域 Interrupt 中断处于WaitSleepJoin线程状态的线程 ResetAbort 取消为当前线程请求的Abort
线程的生命周期
线程的建立与启动
线程的建立与启动 新建一个线程的过程: 只需将其声明并为其提供线程起始点处的方法委托,再用Thread.Start()方法启动该线程 (1)声明: Thread a; (2)实例化 a=new Thread(new ThreadStart(b)); 其中,b为新建过程中执行的过程名。 (3)调用Thread.Start()方法启动该线程 a.Start();
using System; using System.Threading; namespace ThreadDemo1 { class MulitTask { public void PrintData() { for(int i=1;i<=100;i++) Console.Write(i.ToString()+"\t"); } } class Program { public static void Main(string[] args) { MulitTask mt=new MulitTask (); Thread t=new Thread(new ThreadStart(mt.PrintData)); t.Start(); Console.ReadKey(true); } } }
进度条演示 void Button1Click(object sender, EventArgs e){ Thread myThread = new Thread(DoData); files= Directory.GetFiles("c:\\windows"); myThread.Start(files.Length ); //线程开始 }
private delegate void DoDataDelegate(object number); private void DoData(object number) { if (progressBar1.InvokeRequired) { DoDataDelegate d = DoData; progressBar1.Invoke(d, number); } else { progressBar1.Maximum = (int)number; for (int i = 0; i < (int)number; i++) { progressBar1.Value = i; TreeNode node=new TreeNode (); node.Text =files[i]; treeView1.Nodes.Add (node ); } } }
线程的挂起、恢复与终止 其他与操作线程相关的方法 线程的挂起(或暂停) (1)调用Thread.Sleep()方法将线程挂起。 (2)调用s1.Suspend() 方法将线程挂起 区别:前者为静态方法,并且使线程立即暂停一定时间;后者为实例方法,不会使线程立即停止执行,直到线程到达安全点之后,它才将该线程暂停。 线程的恢复与终止 调用Resume()方法将线程恢复; 调用Abort()方法将线程终止; 其他与操作线程相关的方法 Join():使一个线程等待另一个线程停止 Interrupt():中断处于JoinWaitSleep线程状态的线程。
线程的优先级
如果在应用程序中有多个线程在运行,但一些线程比另一些线程重要,该怎么办? 可以在一个进程中为不同的线程指定不同的优先级 线程 1 先执行哪个线程? 线程 2 线程 3 程序 1 如果在应用程序中有多个线程在运行,但一些线程比另一些线程重要,该怎么办? 线程 1 线程 2 线程 3 程序 2 可以在一个进程中为不同的线程指定不同的优先级
线程的优先级 输出结果混乱 将由应用程序线程执行 class SimpleThreadDemo { static void Main(string[] args) Thread.CurrentThread.Name = “主线程"; Thread objThread = new Thread(new ThreadStart(ActionMethod)); objThread.Name = “子线程"; //启动子线程, 并为该线程执行 ActionMethod objThread.Start(); //这将为主线程执行 ActionMethod ActionMethod(); } static void ActionMethod() for(int count = 1; count <= 10 ; count++) Console.WriteLine(“线程名:" + Thread.CurrentThread.Name); 线程的优先级 输出结果混乱 实例化 objThread 线程并开始执行 ActionMethod() 将由应用程序线程执行
线程的优先级 线程是根据其优先级来调度的,每个线程都有特定的优先级。每个线程在创建时其优先级为: ThreadPriority . Normal 线程的优先级定义为ThreadPriority枚举类型,如下表: Normal:普通级别。 AboveNormal:高于普通级别。 BelowNormal:低于普通级别。 Highest:最高级别。 Lowest:最低级别。
线程的优先级 例题1: 无优先级线程,同时执行,输出无序…. static void Main(string[] args) { Thread objThreadOne = new Thread(new ThreadStart(TaskOne)); Thread objThreadTwo = new Thread(new ThreadStart(TaskTwo)); objThreadOne.Start(); objThreadTwo.Start(); } static void TaskOne() { for(int count=1;count<=5;count++) Console.WriteLine(count*2); } static void TaskTwo() { for(int index = 5000;index > =4990; index--) Console.WriteLine(index); } 无优先级线程,同时执行,输出无序….
将在执行第一个线程前执行 objThreadTwo 线程的优先级 例题1: static void Main(string[] args) { Thread.CurrentThread.Name = “主线程"; Thread objThreadOne = new Thread(new ThreadStart(TaskOne)); objThreadOne.Name = “子线程 1"; Thread objThreadTwo = new Thread(new ThreadStart(TaskTwo)); objThreadTwo.Name = “子线程 2"; // 这将启动子线程 objThreadOne.Start(); objThreadTwo.Start(); objThreadTwo.Priority = ThreadPriority.Highest; } 将在执行第一个线程前执行 objThreadTwo
线程同步
线程同步 使用线程的一个重要方面是同步访问多个线程访问的任何变量。 背景:当多个线程共享数据,其中一个或多个线程要修改数据时,有可能引起数据不统一等问题。 同步:是指在某一时刻只有一个线程可以访问某共享数据。
售火车票 银行账户
锁定机制保证每次只有一个线程可以访问共享资源 线程1 共享资源 缓冲和隔离 线程2 程序 锁定机制保证每次只有一个线程可以访问共享资源
同步关键字-lock C#为同步访问变量提供了一个非常简单的方式,即使用C#语言的关键字lock,其用法如下所示: lock (x) { DoSomething(); }
在书店可能某种书籍只有一本,而两个售货员同时销售这本书,我们可以把两个售货员看作两个线程,那该如何处理呢?
class BookShop { public static int count = 1; public void Sale() lock (this) if (count > 0) count = count - 1; Thread.Sleep(1000); Console.WriteLine("{0}卖出去了一本,现在还剩下{1}本", Thread.CurrentThread.Name, count); } else Console.WriteLine("{0}说:对不起,卖完了", Thread.CurrentThread.Name);
class Program { static void Main(string[] args) BookShop bookShop = new BookShop(); Thread t1 = new Thread(new ThreadStart(bookShop.Sale)); Thread t2 = new Thread(new ThreadStart(bookShop.Sale)); t1.Name = "小赵"; t2.Name = "小张"; t1.Start(); t2.Start(); }
银行取钱 本示例建立了10个线程 using System; using System.Threading; // 银行帐户类 // 银行帐户类 class Account { int balance; // 余额 Random r = new Random(); public Account(int initial) { balance = initial; }
// 取钱 int Withdraw(int amount) { if (balance < 0) { throw new Exception("余额为负!"); } lock (this){ if (balance >= amount) { Console.WriteLine("原有余额: " + balance); Console.WriteLine("支取金额: -" + amount); balance = balance - amount; Console.WriteLine("现有余额: " + balance); return amount; else { return 0; // 拒绝交易
// 测试交易 public void DoTransactions() { // 支取随机的金额100次 for (int i = 0; i < 100; i++) { Withdraw(r.Next(1, 100)); } class TestApp{ public static void Main() {// 建立10个线程同时进行交易 Thread[] threads = new Thread[10]; Account acc = new Account (1000); for (int i = 0; i < 10; i++) { Thread t = new Thread(new ThreadStart(acc.DoTransactions)); threads[i] = t; threads[i].Start();
总结 线程是在共享内存空间中并发的多道执行路径 在 C# 中,是使用 System.Threading 命名空间中的 Thread 类来创建线程的 线程优先级可以更改为 ThreadPriority 枚举中定义的一个值 C# 中的 lock 关键字是实现线程同步的一种方法 同步的线程称为安全线程 除非绝对必要,否则不要创建线程安全的代码,因为添加不必要的锁定会降低性能