线程几乎是所有项目或多或少都在用的一种技术手段了,在WPF项目中更是用的只会多不会少的。所以通过WPF的世界来介绍下线程。学习过《计算机操作系统》的基本很容易去理解线程和同/异步有多么的重要,进程、线程和同/异步的出现是让我们的计算机有这么大发展的基础之一。WPF的多线程和window窗体中的多线程基本一样,只是实现的细节和底层支持有点不一样。
我们的程序通常会执行很多的任务,在我们没处理的正常情况下任务都是同步进行的,也就是说在这个应用程序中一次只能执行一个任务,当这个任务执行结束了,才会去执行下一个任务。在这种情况下,长时间的占用就意味着长时间的等待,这个叫做线程阻塞,不仅很影响用户体验,拖累性能,更严重的还让人误以为程序死了。
为了避免线程阻塞,牛逼的前辈这时候就创造了后台线程,并且允许异步操作这种技术出来了。是的,多线程和同步、异步不是一个事。当后台线程完成自己的任务后,它是可以通知到程序的,这个时候程序会接着做自己事,这个叫做“线程同步”。是不是有点绕,我说明下,就像物理一样,同步异步只是参照物不同,AB任务是并列执行的异步操作,AC也许是同步执行的操作。
正常情况下WPF的对象只属于创建它的线程,而不会被其它线程所直接访问。就是说你一个后台线程是不能去访问主线程的用户界面的所有对象,比如改一个TextBox的值。当一个对象呗关联到一个单线程时,就认为它是一个单线程对象,并且认为该对象具有线程关联度。WPF觉得这样不太方便,所以能创造了一个STA(Single Threaded Apartment)模型去解决这个问题,并同时保证了它跨线程访问的安全性。后台线程访问主程序窗口用法就是具体方法是强制使用DispatcherObject,在窗体的Main()入口点,标记[STAThread]。
线程关联度与DispatcherObject
一定要明确,一个具有线程关联度的对象只能在创建它的线程中访问。每一个线程模型的WPF对象都直接或者间接的继承自DispatcherObject类,包括Application、Visual、DependencyObject。大多数框架基本都继承自DependencyObject,所以说几乎所有的用户界面元素也具有线程关联度。因为DispatcherObject强制使用线程关联度,所以WPF对象是线程安全的。
DispatcherObject提供两个方法,VerifyAccess和CheackAccess,用于确定一个对象是否在正确的线程上,它会返回一个Boolean值,如果不在会抛出一个异常。
分发器
应用程序需要一种机制对用户和系统的输入(比如鼠标事件、键盘事件等)操作做出反应,这叫做消息循环。Windows会把每个消息放在消息队列中,消息循环不断监视这个消息队列并向程序分发消息。所以可以理解消息队列和消息循环有分发器创建和管理。一个分发器是Dispatcher类一个实例。分发器根据任务的优先级,每次运行一个任务。
WPF中只有一个主线程,就是用户界面,其他的线程也叫做工作者线程,在后台执行任务。为了使后台线程和主界面交互,就必须用用户界面的分发器传递消息。分发器和创建它的线程使一对一的。
一个线程是不能直接访问另一个线程的对象的,否则会抛出异常。Dispatcher类提供了Invoke和BeginInvoke两个方法,后台线程可以使用这两个方法在用户界面上安排任务,并明确委托分发器可以修改目标对象。
创建线程的4种方式
①、正常创建
Thread thread1 = new Thread(new ThreadStart(method));
②、匿名委托创建线程
Thread thread2 = new Thread(delegate() { function1() ;});
③、lambda表达式创建线程
Thread thread3 = new Thread(()=> function1() ;));
④、有参委托创建线程
Thread thread4 = new Thread(new ParameterizedThreadStart(method2));
线程安全的一些方法
①、使用Mutex互斥锁,用于多线程间的线程同步通过WaitOne等待当前锁定的线程执行完成,例如,线程B执行需要等待线程A执行结束的情况下,可以使用Mutex
’②、使用AutoResetEvent,从字面即可知道是自动信号,意思为当信号被捕捉之后会自动重置为关闭状态;
③、使用Lock,Lock只能锁住一个引用类型的对象。另外,除了锁机制外,高版本的C#中加入了async和await方法来保证线程安全
————————————————
版权声明:本文为CSDN博主「拓拓龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/TOTOLOG/article/details/102499850
我们的程序通常会执行很多的任务,在我们没处理的正常情况下任务都是同步进行的,也就是说在这个应用程序中一次只能执行一个任务,当这个任务执行结束了,才会去执行下一个任务。在这种情况下,长时间的占用就意味着长时间的等待,这个叫做线程阻塞,不仅很影响用户体验,拖累性能,更严重的还让人误以为程序死了。
为了避免线程阻塞,牛逼的前辈这时候就创造了后台线程,并且允许异步操作这种技术出来了。是的,多线程和同步、异步不是一个事。当后台线程完成自己的任务后,它是可以通知到程序的,这个时候程序会接着做自己事,这个叫做“线程同步”。是不是有点绕,我说明下,就像物理一样,同步异步只是参照物不同,AB任务是并列执行的异步操作,AC也许是同步执行的操作。
正常情况下WPF的对象只属于创建它的线程,而不会被其它线程所直接访问。就是说你一个后台线程是不能去访问主线程的用户界面的所有对象,比如改一个TextBox的值。当一个对象呗关联到一个单线程时,就认为它是一个单线程对象,并且认为该对象具有线程关联度。WPF觉得这样不太方便,所以能创造了一个STA(Single Threaded Apartment)模型去解决这个问题,并同时保证了它跨线程访问的安全性。后台线程访问主程序窗口用法就是具体方法是强制使用DispatcherObject,在窗体的Main()入口点,标记[STAThread]。
线程关联度与DispatcherObject
一定要明确,一个具有线程关联度的对象只能在创建它的线程中访问。每一个线程模型的WPF对象都直接或者间接的继承自DispatcherObject类,包括Application、Visual、DependencyObject。大多数框架基本都继承自DependencyObject,所以说几乎所有的用户界面元素也具有线程关联度。因为DispatcherObject强制使用线程关联度,所以WPF对象是线程安全的。
DispatcherObject提供两个方法,VerifyAccess和CheackAccess,用于确定一个对象是否在正确的线程上,它会返回一个Boolean值,如果不在会抛出一个异常。
分发器
应用程序需要一种机制对用户和系统的输入(比如鼠标事件、键盘事件等)操作做出反应,这叫做消息循环。Windows会把每个消息放在消息队列中,消息循环不断监视这个消息队列并向程序分发消息。所以可以理解消息队列和消息循环有分发器创建和管理。一个分发器是Dispatcher类一个实例。分发器根据任务的优先级,每次运行一个任务。
WPF中只有一个主线程,就是用户界面,其他的线程也叫做工作者线程,在后台执行任务。为了使后台线程和主界面交互,就必须用用户界面的分发器传递消息。分发器和创建它的线程使一对一的。
一个线程是不能直接访问另一个线程的对象的,否则会抛出异常。Dispatcher类提供了Invoke和BeginInvoke两个方法,后台线程可以使用这两个方法在用户界面上安排任务,并明确委托分发器可以修改目标对象。
创建线程的4种方式
①、正常创建
Thread thread1 = new Thread(new ThreadStart(method));
②、匿名委托创建线程
Thread thread2 = new Thread(delegate() { function1() ;});
③、lambda表达式创建线程
Thread thread3 = new Thread(()=> function1() ;));
④、有参委托创建线程
Thread thread4 = new Thread(new ParameterizedThreadStart(method2));
线程安全的一些方法
①、使用Mutex互斥锁,用于多线程间的线程同步通过WaitOne等待当前锁定的线程执行完成,例如,线程B执行需要等待线程A执行结束的情况下,可以使用Mutex
’②、使用AutoResetEvent,从字面即可知道是自动信号,意思为当信号被捕捉之后会自动重置为关闭状态;
③、使用Lock,Lock只能锁住一个引用类型的对象。另外,除了锁机制外,高版本的C#中加入了async和await方法来保证线程安全
————————————————
版权声明:本文为CSDN博主「拓拓龙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/TOTOLOG/article/details/102499850