C# 线程---Thread1

news/2024/10/11 17:45:28

 

1. thread 不带参数 (Main和Thread都在同步处理)(注意using static 和System.Console的使用)

using static System.Console;namespace Recipe1
{class Program{static void Main(string[] args){Thread t = new Thread(PrintNumber);t.Start();PrintNumber();Read();}static void PrintNumber(){WriteLine("Starting...");for (int i = 1; i < 10; i++){WriteLine( i);Thread.Sleep(100);}}}
}
View Code

2. 暂停(休眠)线程,展示如何让一个线程等待一段时间而不用消耗操作系统资源,虽然先启动,但还是后运行。(sleep当线程处于休眠状态时,它会占用尽可能少的CPU时间)

class Program{static void Main(string[] args){Thread t = new Thread(PrintNumbersWithDelay);t.Start();PrintNumbers();}static void PrintNumbers(){WriteLine("Starting PrintNumbers...");for (int i = 1; i < 10; i++){WriteLine("PrintNumbers"+i);}}static void PrintNumbersWithDelay(){WriteLine("Starting PrintNumbersWithDelay...");for (int i = 1; i < 10; i++){Sleep(TimeSpan.FromSeconds(2));WriteLine("PrintNumbersWithDelay "+i);}}}
View Code

 3. 等待线程完成,再往下走(t.Join() ,主线程处于阻塞状态(啥也不干),等待t这个线程完成,当线程t完成 时,主程序会继续运行

class Program{static void Main(string[] args){WriteLine("Starting program...");Thread t = new Thread(PrintNumbersWithDelay);t.Start();t.Join();WriteLine("Thread completed");}static void PrintNumbersWithDelay(){WriteLine("Starting...");for (int i = 1; i < 10; i++){Sleep(TimeSpan.FromSeconds(2));WriteLine(i);}}}
View Code

4. 线程中途中止(t.Start();Sleep(TimeSpan.FromSeconds(6));t.Abort(); 我们等待6秒后对线程调用了 t.Abort方法 这给线程注入了 ThreadAbortException方法,导致线程被终结。这非常危险,因为该异常可 以在任何时刻发生并可能彻底摧毁应用程序;另外,使用该技术也不一定总能终止线程。目 标线程可以通过处理该异常并调用Thread.ResetAbort方法来拒绝被终止因此并不推荐使用 Abort方法来关闭线程°可优先使用一些其他方法.比如提供一个CancellationToken方法来 取消线程的执行

class Program{static void Main(string[] args){WriteLine("Starting program...");Thread t = new Thread(PrintNumbersWithDelay);t.Start();Sleep(TimeSpan.FromSeconds(6));t.Abort();WriteLine("A thread has been aborted");}static void PrintNumbersWithDelay(){WriteLine("Starting...");for (int i = 1; i < 10; i++){Sleep(TimeSpan.FromSeconds(2));WriteLine(i);}}}
View Code

5. 描述一个线程可能会有哪些状态.获取线程是否已经启动或是否处于阻塞状态等(状态位于Thread对象的ThreadState属性中 ThreadState属性是一个C#枚举对象)

 1 static void Main(string[] args)
 2         {
 3             WriteLine("Main Starting program...");
 4             Thread t = new Thread(PrintNumbersWithStatus);
 5             Thread t2 = new Thread(DoNothing);
 6             WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
 7             t2.Start();
 8             t.Start();
 9             for (int i = 1; i < 30; i++)
10             {
11                 WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
12             }
13             Sleep(TimeSpan.FromSeconds(6));
14             t.Abort();
15             WriteLine("PrintNumbersWithStatus thread has been aborted");
16             WriteLine("PrintNumbersWithStatus:"+t.ThreadState.ToString());
17             WriteLine("DoNothing:"+t2.ThreadState.ToString());
18             Read();
19         }
20 
21         static void DoNothing()
22         {
23             Sleep(TimeSpan.FromSeconds(2));
24         }
25 
26         static void PrintNumbersWithStatus()
27         {
28             WriteLine("PrintNumbersWithStatus Starting...");
29             WriteLine("PrintNumbersWithStatus"+CurrentThread.ThreadState.ToString());
30             for (int i = 1; i < 10; i++)
31             {
32                 Sleep(TimeSpan.FromSeconds(2));
33                 WriteLine("PrintNumbersWithStatus "+i);
34             }
35         }
线程各阶段状态

 

 6. 线程优先级(线程优先级决定了该线程可占用多少 CPU时间)

如果拥有一个 以上的计算核心,将在两秒钟内得到初步结果,两个值应该很接近〉然而,如果有其他程序占用了所有的CPU核心运行负载,CPU核心大部分时间在运行高优先级的线程,只留给剩下的线程很少的时间来 运行,为了模拟该情形,我们设置了 ProcessorAffinity选项,止操作系统将所有的线程运 行在单个CPU核心(第一个核心)上。

class Program{static void Main(string[] args){WriteLine($"Current thread priority: {CurrentThread.Priority}");WriteLine("Running on all cores available");RunThreads();Sleep(TimeSpan.FromSeconds(2));WriteLine("Running on a single core");GetCurrentProcess().ProcessorAffinity = new IntPtr(1);RunThreads();}static void RunThreads(){var sample = new ThreadSample();var threadOne = new Thread(sample.CountNumbers);threadOne.Name = "ThreadOne";var threadTwo = new Thread(sample.CountNumbers);threadTwo.Name = "ThreadTwo";threadOne.Priority = ThreadPriority.Highest;threadTwo.Priority = ThreadPriority.Lowest;threadOne.Start();threadTwo.Start();Sleep(TimeSpan.FromSeconds(2));sample.Stop();}class ThreadSample{private bool _isStopped = false;public void Stop(){_isStopped = true;}public void CountNumbers(){long counter = 0;while (!_isStopped){counter++;}WriteLine($"{CurrentThread.Name} with " +$"{CurrentThread.Priority,11} priority " +$"has a count = {counter,13:N0}");}}}
线程优先级

7. 前台线程和后台线程(进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结 束工作)

static void Main(string[] args){var sampleForeground = new ThreadSample(10);var sampleBackground = new ThreadSample(20);var threadOne = new Thread(sampleForeground.CountNumbers);threadOne.Name = "ForegroundThread";var threadTwo = new Thread(sampleBackground.CountNumbers);threadTwo.Name = "BackgroundThread";threadTwo.IsBackground = true;threadOne.Start();threadTwo.Start();}class ThreadSample{private readonly int _iterations;public ThreadSample(int iterations){_iterations = iterations;}public void CountNumbers(){for (int i = 0; i < _iterations; i++){Sleep(TimeSpan.FromSeconds(0.5));WriteLine($"{CurrentThread.Name} prints {i}");}}}
前台线程和后台线程

8. 向线程传递参数

using static System.Threading.Thread;namespace Recipe1
{class Program{static void Main(string[] args){//通过ThreadSample对象的构造函数传入,再启动线程var sample = new ThreadSample(10);var threadOne = new Thread(sample.CountNumbers);threadOne.Name = "ThreadOne";threadOne.Start();threadOne.Join();WriteLine("--------------------------");//使用Thread.Start方法接收一个对象给线程。必须接受object类型的单个参数var threadTwo = new Thread(Count);threadTwo.Name = "ThreadTwo";threadTwo.Start(8);threadTwo.Join();WriteLine("--------------------------");//lambda表达式定义了一个不属于任何类的方法。 该方法使用需要的参数调用了另一个方法,并在另一个线程中运行该方法var threadThree = new Thread(() => CountNumbers(12));threadThree.Name = "ThreadThree";threadThree.Start();threadThree.Join();WriteLine("--------------------------");int i = 10;var threadFour = new Thread(() => PrintNumber(i));i = 20;var threadFive = new Thread(() => PrintNumber(i));threadFour.Start();threadFive.Start();Read();}static void Count(object iterations){CountNumbers((int)iterations);}static void CountNumbers(int iterations){for (int i = 1; i <= iterations; i++){Sleep(TimeSpan.FromSeconds(0.5));WriteLine($"{CurrentThread.Name} prints {i}");}}static void PrintNumber(int number){WriteLine(number);}class ThreadSample{private readonly int _iterations;public ThreadSample(int iterations){_iterations = iterations;}public void CountNumbers(){for (int i = 1; i <= _iterations; i++){Sleep(TimeSpan.FromSeconds(0.5));WriteLine($"{CurrentThread.Name} prints {i}");}}}}
}
线程各种带参数的方式

9. 线程中的锁(产生死锁)

三个线程共享同一个counter实例,在一个周期 中进行一次递增和一次递减。这将导致不确定的结果(这是因为Counter类并不是线程安全的。当多个线程同时访问counter对象时,第一个 线程得到的counter10并增加为1"然后第二个线程得到的值是11并增加为12。第一个 线程得到counter12,但是递减操作发生前,第二个线程得到的counter值也是12。然后 第一个线程将12递减为11并保存回counter中,同时第二个线程进行了同样的操作。结果 我们进行了两次递增操作但是只有一次递减操作,这显然不对)

为了确保不会发生以上情形,必须保证当有线程操作counter对象时,所有其他线程必 须等待直到当前线程完成操作。我们可以使用lock关键字来实现这种行为。如果锁定了一个 对象,需要访问该对象的所有其他线程则会处于阻塞状态,并等待直到该对象解除锁定。这 可能会导致严重的性能问题

 

using System;
using System.Threading;
using static System.Console;namespace Chapter1.Recipe9
{class Program{static void Main(string[] args){WriteLine("Incorrect counter");var c = new Counter();var t1 = new Thread(() => TestCounter(c));var t2 = new Thread(() => TestCounter(c));var t3 = new Thread(() => TestCounter(c));t1.Start();t2.Start();t3.Start();t1.Join();t2.Join();t3.Join();WriteLine($"Total count: {c.Count}");WriteLine("--------------------------");WriteLine("Correct counter");var c1 = new CounterWithLock();t1 = new Thread(() => TestCounter(c1));t2 = new Thread(() => TestCounter(c1));t3 = new Thread(() => TestCounter(c1));t1.Start();t2.Start();t3.Start();t1.Join();t2.Join();t3.Join();WriteLine($"Total count: {c1.Count}");Read();}static void TestCounter(CounterBase c){for (int i = 0; i < 100000; i++){c.Increment();c.Decrement();}}class Counter : CounterBase{public int Count { get; private set; }public override void Increment(){Count++;}public override void Decrement(){Count--;}}class CounterWithLock : CounterBase{private readonly object _syncRoot = new Object();public int Count { get; private set; }public override void Increment(){lock (_syncRoot){Count++;}}public override void Decrement(){lock (_syncRoot){Count--;}}}abstract class CounterBase{public abstract void Increment();public abstract void Decrement();}}
}
线程加锁

10. Monitor类锁定资源(避免死锁)

产生死锁的过程:在该方法中我们先锁定了第一个对象,等待一秒后锁定了 第二个对象。然后在另一个线程中启动该方法。最后尝试在主线程中先后锁定第二个和第一 个对象。

如果像该示例的第二部分一样使用lock关键字,将会造成死锁。第一个线程保持对 lockl对象的锁定,等待直到lock2对象被释放。主线程保持对lock2对象的锁定并等待直到 lockl对象被释放,但lockl对象永远不会被释放。

我们可以直接使用Monitor类。其拥有TryEnter方法,该方法接受一个超时参 数。如果在我们能够获取被lock保护的资源之前,超时参数过期,则该方法会返回false

using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;namespace Chapter1.Recipe10
{class Program{static void Main(string[] args){object lock1 = new object();object lock2 = new object();new Thread(() => LockTooMuch(lock1, lock2)).Start();lock (lock2){Thread.Sleep(1000);WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5))){WriteLine("Acquired a protected resource succesfully");}else{WriteLine("Timeout acquiring a resource!");}}new Thread(() => LockTooMuch(lock1, lock2)).Start();WriteLine("----------------------------------");lock (lock2){WriteLine("This will be a deadlock!");Sleep(1000);lock (lock1){WriteLine("Acquired a protected resource succesfully");}}}static void LockTooMuch(object lock1, object lock2){lock (lock1){Sleep(1000);lock (lock2);}}}
}
避免死锁

11.线程中处理异常

当主程序启动时,定义了两个将会抛出异常的线程。其中一个对异常进行了处理,另 一个则没有。可以看到第二个异常没有被包裹启动线程的try/catch代码块捕获到。所以 如果直接使用线程,一般来说不要在线程中抛出异常,而是在线程代码中使用try/catch 代码块

using System;
using System.Threading;
using static System.Console;
using static System.Threading.Thread;namespace Chapter1.Recipe11
{class Program{static void Main(string[] args){var t = new Thread(FaultyThread);t.Start();t.Join();try{t = new Thread(BadFaultyThread);t.Start();}catch (Exception ex){WriteLine("We won't get here!");}}static void BadFaultyThread(){WriteLine("Starting a faulty thread...");Sleep(TimeSpan.FromSeconds(2));throw new Exception("Boom!");}static void FaultyThread(){try{WriteLine("Starting a faulty thread...");Sleep(TimeSpan.FromSeconds(1));throw new Exception("Boom!");}catch (Exception ex){WriteLine($"Exception handled: {ex.Message}");}}}
}
线程中异常(try catch)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/70300.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

解决 java.lang.VerifyError: Stack map does not match the one at exception

项目上用的liteflow,动态编译代码,在项目执行过程中报错如下: 拿到异常信息网上搜索,网上的说法如下: VM加载class文件时会做字节码校验(bytecode verification)。如果你的class文件是由java源文件通过javac编译出来的,那么基本上不用担心bytecode verification。 如果…

婚恋结构相亲管理系统的技术性分析

随着社会发展和人们对婚恋关系的重视,婚恋交友市场逐渐崛起。婚恋结构相亲管理系统作为该市场的重要解决方案,通过互联网平台将用户和服务提供者连接起来,帮助用户高效地寻找和管理自己的婚恋关系。本文将深入探讨婚恋结构相亲管理系统的技术架构、核心功能及其实现方式。一…

笔记本电脑蓝屏固态硬盘数据恢复

当笔记本电脑出现蓝屏故障,并且需要恢复固态硬盘中的数据时,可以参考以下步骤和建议: 一、初步处理与评估 断开电源:在尝试任何数据恢复操作之前,首先要断开笔记本电脑的电源,以避免进一步的数据损坏或丢失。 评估蓝屏原因:蓝屏可能是由多种原因引起的,如驱动程序错误、…

20222307 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1. 实验内容 1.1本周学习内容 进程内存管理 在Linux系统中,当OS可执行程序被加载到内存后,其内存布局主要包括三个关键段: * .text段:包含程序的指令,这些指令是只读的,用于指导CPU执行操作。 * .data段:存储静态初始化数据,这些数据是可写的,程序在运行时可以直接访问…

WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

1、新建了一个用户控件,里面画了一个实心圆,以及一个文本控件的组合,当作我要实验使用的用户控件(TestUserControl)。2、在主窗体里面进行引用,可以看到引用以后,会在工具箱上显示新增的用户控件3、为了测试方便,我直接在先前的Login页面直接进行添加该用户控件,效果如下…

华为交换机配置-端口隔离

端口隔离(port-isolate) 1.端口隔离 配置端口隔离功能,可实现本台交换机的两个接口之间的二层数据的隔离,而三层数据互通 拓扑图<sw1>sys //配置全局端口隔离模式为二层隔离(l2)、三层隔离(l3) [sw1]port-isolate mode l2 [sw1]interface GigabitEthernet 0/0/1 …

Sublime

Sublime激活快捷键 Alt + F3 查找内容 全部选择,可以统一替换或 手动修改

20222418 2024-2025-1 《网络与系统攻防技术》实验一实验报告

1.实验内容 本周课程内容为缓冲区溢出和shellcode:2.实验过程 (1)直接修改程序机器指令,改变程序执行流程 ①首先根据网上教程安装好kali虚拟机,更改主机名为heshan;下载目标文件pwn1,将pwn1文件放入共享文件夹并在VMware中设置共享以便使用,并将其重命名为pwn20222418…