在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
19.1 多线程编程知识19.1.1 进程与线程的概念进程:
线程:
进程与线程的关系
线程是进程的执行单元,操作系统通过调度线程使应用程序工作。
进程是线程的容器,由操作系统创建,由在具体的执行过程中创建线程。
19.1.2 线程的调度生活中吃饭的时候看电视,你需要来回切换这两个动作,他们由你来进行调度的。计算机里,线程相当于你的动作,操作系统相当于你,操作系统需要调度线程使他们轮流工作。
Windows是抢占式多线程系统。因为线程可以在任意事件里被抢占,来调度另一个线程。操作系统为每个线程分配了0~31某一优先级,优先级高的优先分配给CPU。
windows 支持7个相对线程优先级,Idle、Lowest、BelowNormal、Normal、AboveNormal、Highest、Time-Critical 。程序可以设置 Thread 的 Priority 属性来改变线程的优先级,该属性为 ThreadPriority 枚举类型,成员包含了 Lowest、BelowNormal、Normal、AboveNormal、Highest,CLR 为自己保留了 Idle、Time-Critical
1、Time-critical:关键时间(最高的相对线程优先级) 2、Heightest:最高(翻译是这么翻译,但是并不是最高的相对线程优先级) 3、Above normal:高于标准 4、Normal:标准 5、Below normal:低于标准 6、Lowest:最低(翻译是这么翻译,但是并不是最低的相对线程优先级) 7、Idle:空闲 19.1.3 线程也分前后台
前台线程:只有所有的前台线程都关闭才能完成程序关闭。(主线程一直是前台线程)
后台线程:只要所有的前台线程都结束,后台线程自动结束(CLR会强制结束所有仍运行的后台线程,却不会抛出异常)。
CLRT + F5 (不调试)效果图 上面代码通过 Thread 创建一个线程对象,设置 IsBackground 属性指明线程为后台线程。不设置 IsBackground 属性,则所创建的线程默认为前台线程。
接着,调用 Start 函数启动该线程,此时后台线程会执行 Worker 函数代码。
从前面分析中看出,该控制台有两个线程,一个运行 Main 函数的主线程,另一个运行 Worker 函数的后台线程。由于前台执行完毕后 CLR 会无条件终止后台线程运行,所以前面代码中若启动后台线程,则主线程将会继续运行。
主线程运行完 Console.WriteLine( "从主线程中退出") 语句就会退出。此时, CLR 发现主线程运行结束,则会终止后台线程,然后整个程序结束运行。所以 Worker 函数中的 Console.WriteLine("从后台线程退出") 语句将不会执行。
通过分析,按 CLRT + F5 运行程序,你将会看到如图效果。如果按 F5 你将会看到输出结果一闪而过,因为主线程退出后,整个应用程序也跟着退出,就关闭了控制台程序。
分析执行后台线程的方法
1.所创建线程默认为非后台线程,所以注释掉 //backThread.IsBackground = true;(这时候不是后台线程了) 2.使主线程在后台线程执行完毕后再执行,即使主线程进入睡眠,且睡眠时间比后台线程长。
3.通过调用主函数的 Join 函数方法,确保主线程会在后台线程执行结束后开始运行。
以上代码调用 backThread.Start() 确保主线程会在后台线程结束后再运行。这种方式涉及
线程同步的概念:在某些情况下,需要两个线程同步运行。即一个线程必须等待另外一个线程结束之后才能运行。
// System.Threading.ParameterizedThreadStart 委托,它表示此线程开始执行时要调用的方法。
public Thread(ParameterizedThreadStart start);
// System.Threading.ThreadStart 委托,它表示此线程开始执行时要调用的方法。
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
ParameterizedThreadStart 与 ThreadStart 的区别:ParameterizedThreadStart 可以有参数,ThreadStart 没有参数。本实例就是创建的ThreadStart。
19.2 线程的容器——线程池通过 Thread 类手动创建线程的创建和销毁会耗费大量时间,这样的手动操作将造成性能的损失。因此,.NET引入了线程池机制。
19.2.1 线程池
19.2.2 通过线程池来实现多线程使用线程池的线程,要调用静态方法 ThreadPool.QueueUserWorkItem ,以指定线程要调用的方法。该静态方法有两种: public static bool QueueUserWorkItem(WaitCallback callBack); public static bool QueueUserWorkItem(WaitCallback callBack, object state);
19.2.3 协作式取消线程池线程.NET Framework 提供了取消操作的模式,这个模式是协作式的。为了取消操作,我们必须创建一个 System.Threading.CancellationTokenSource 对象。
首先创建一个 CancellationTokenSource 实例,将该实例作为参数传入QueueUserWorkItem 方法。线程池会创建一个线程池线程,运行该方法传入的回调函数 callback ,并在 callback 中执行 Count 函数来计数。 在 Count 函数中检查 CancellationTokenSource 类实例的状态。当用户按回车键时,该实例的 IsCancellationRequested 属性将返回 ture 。因此退出 Count 方法。否则一直运行。 19.3 线程同步多线程中,为了保证后者线程,只有等待前者线程完成之后才能继续执行。好比排队买票,前面的人没买票之前,后面的人必须等待。 19.3.1 多线程程序中存在的隐患多线程可以提高程序的性能和用户体验。然而当我们创建多个线程后,它们可能同时访问某一个共享资源,这将损坏资源中所保存的数据。这时候我们需要使用线程同步,确保某一时刻只有一个线程在操作共享资源。 举例来说,火车票销售系统允许多人同时购买,因此该系统肯定采用了多线程技术。但由于系统中有多个线程在对同一资源(火车票)进行操作,我们必须确保只有其他线程执行结束后,新的线程才开始执行。这样可以避免多位顾客买到同一张票。 |
请发表评论