当前位置:首页 > Windows程序 > 正文

学习C#异步编程

2024-03-31 Windows程序

"杨老师视频教程"

P1 线程(Thread):创建线程

视频地址

什么是线程Thread

线程是一个可执行路径,它可以独立于其它线程执行

每个线程都在操作系统的进程(Process)内执行,而操作系统进程提供了程序运行的独立环境。

单线程应用,在进程的独立环境里 只跑一个线程,所以该线程拥有独占权。

多线程应用,单个进程中会跑多个线程,它们会共享当前的执行环境(尤其是内存)

例如,一个线程在后台读取数据,另一个线程在数据到达后进行展示。

这个数据就被称作是共享的状态。

例子:

class Program { static void Main(string[] args) { Thread thread = new Thread(WriteY); //开启一个新的线程 Thread thread.Name = "Y Thread..."; thread.Start(); for (int i = 0; i < 1000; i++) Console.WriteLine("x"); Console.ReadKey(); } private static void WriteY() { for(int i = 0; i < 1000; i++) { Console.WriteLine("y"); } } }

在单核计算机上,操作系统必须为每个线程分配“时间片”(在Windows中通常为20毫秒)来模拟并发,从而导致重复的x和y块。

在多核或多处理器计算机上,这两个线程可以真正地并行执行(可能受到计算机上其他活动进程的竞争)。

术语:线程被抢占

线程在什么时候可以称为被抢占了:它的执行与另一个线程上代码的执行交织的那一刻。

线程的一些属性

线程一旦开始执行,IsAlive就是true,线程结束就变成false。

线程结束的条件就是:线程构造函数传入的委托结束了执行。

线程一旦结束,就无法再重启。

每个线程都有个Name属性,通常用于调试

线程Name只能设置一次,以后更改会抛出异常。(System.InvalidOperationException:“该属性已经设置,不能修改。”)

静态的Thread.CurrentThread属性,会返回当前执行的线程。

P2 Thread.Join()&Thread.Sleep()

视频地址

Join and Sleep

调用Join方法,就可以等待另一个线程结束。

例子:

class Program { static void Main(string[] args) { Thread t = new Thread(WriteY); t.Start(); t.Join();//当前线程会等待t线程执行结束 Console.WriteLine("线程结束"); Console.Read(); } private static void WriteY() { for(int i = 0; i < 1000; i++) { Console.Write("y"); } } } class Program { static Thread thread1, thread2; static void Main(string[] args) { thread1 = new Thread(ThreadProc); thread1.Name = nameof(thread1); thread1.Start(); thread2 = new Thread(ThreadProc); thread2.Name = nameof(thread2); thread2.Start(); Console.Read(); } private static void ThreadProc() { Console.WriteLine($"\nCurrent Thread:{Thread.CurrentThread.Name}"); if (Thread.CurrentThread.Name == nameof(thread1) && thread2.ThreadState != ThreadState.Unstarted) thread2.Join(); Thread.Sleep(4000); Console.WriteLine($"\nCurrent thread:{Thread.CurrentThread.Name}"); Console.WriteLine($"Thread1:{thread1.ThreadState}"); Console.WriteLine($"Thread2:{thread2.ThreadState}"); } }

输出内容:

Current Thread:thread1

Current Thread:thread2

Current thread:thread2
Thread1:WaitSleepJoin
Thread2:Running

Current thread:thread1
Thread1:Running
Thread2:Stopped

添加超时

调用Join的时候,可以设置一个超时,用毫秒或者TimeSpan都可以。

如果返回true,那就是线程结束了,如果超时了,就返回false。

例子:

class Program { static Thread thread1, thread2; static void Main(string[] args) { thread1 = new Thread(ThreadProc); thread1.Name = nameof(thread1); thread1.Start(); thread2 = new Thread(ThreadProc); thread2.Name = nameof(thread2); thread2.Start(); Console.Read(); } private static void ThreadProc() { Console.WriteLine($"\nCurrent Thread:{Thread.CurrentThread.Name}"); if (Thread.CurrentThread.Name == nameof(thread1) && thread2.ThreadState != ThreadState.Unstarted) if (thread2.Join(2000)) Console.WriteLine("线程2结束"); else Console.WriteLine("线程2超时了"); Thread.Sleep(4000); Console.WriteLine($"\nCurrent thread:{Thread.CurrentThread.Name}"); Console.WriteLine($"Thread1:{thread1.ThreadState}"); Console.WriteLine($"Thread2:{thread2.ThreadState}"); } }

输出:

Current Thread:thread1

Current Thread:thread2
线程2超时了

Current thread:thread2
Thread1:WaitSleepJoin
Thread2:Running

Current thread:thread1
Thread1:Running
Thread2:Stopped

Thread.Sleep()方法会暂停当前的线程,并等待一段时间。

注意:

Thread.Sleep(0)这样调用会导致线程立即放弃本身当前的时间片,自动将CPU移交给其他线程。

Thread.Yield()做同样的事情,但是它只会把执行交给同一处理器上的其它线程。

当等待Sleep或Join的时候,线程处于阻塞的状态。

Sleep(0)或Yield有时在高级性能调试的生产代码中很有用。它也是一个很好的诊断工具,有助于发现线程安全问题:

如果在代码中的任何地方插入Thread.Yield()就破坏了程序,那么你的程序几乎肯定有bug。

P3 阻塞Blocking

视频地址

阻塞

如果线程的执行由于某种原因导致暂停,那么就认为该线程被阻塞了。

例如在Sleep或者通过Join等待其它线程结束。

被阻塞的线程会立即将其处理器的时间片生成给其它线程,从此就不再消耗处理器时间,直到满足其阻塞条件为止。

可以通过ThreadState这个属性来判断线程是否处于被阻塞的状态:

bool blocked = (thread.ThreadState & ThreadState.WaitSleepJoin) != 0;

ThreadState

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/43495.html

Jm-杰米博客Jamie
草根站长的技术交流乐园!IT不会不要紧快来好好学习吧!
  • 20786文章总数
  • 7494595访问次数
  • 建站天数
  • 友情链接