C#笔记19:多线程之线程启动、参数、返回值

摘要:
线程启动、参数和多线程的返回值本章概述了:线程传递参数并获得返回值3:线程传递了参数并获得了返回值。线程有两个构造函数,这表明线程不能将参数带入构造函数。Thread1=newThread(newThreadStart(委托{MessageBox.Show(arg1.ToString()+arg2);

C#笔记19:多线程之线程启动、参数、返回值

本章概要:
1:如何新起线程
2:Thread传参数及取得返回值
3:IsBackground
4:异步调用中的参数和返回值


 

1:如何新起线程

     新起一个线程的方法,可以使用Thread,BackgroundWorker ,ThreadPool,控件.BeginInvoke,委托.BeginInvoke,Timer。
    创建多线程处理应用程序的最可靠方法是使用 BackgroundWorker 组件。但是,当你需要对线程进行精细控制的时候,就需要Thread。总体来说,各种方法各有各的优点,在这里不做细说。

     备注:严格意义上,异步不是新线程。

2:Thread传参数及取得返回值

     Thread的有两个构造函数,其中一个使用参数是ThreadStart,说明该线程在构造函数中不能带入参数。还有一个ParameterizedThreadStart,则可以为你的线程传入参数。还有一个方法是为你的线程方法提供一个包裹类,这也可以解决返回值的问题。不过,这种方法在我看来是最丑陋的写法(参考http://msdn.microsoft.com/zh-cn/library/wkays279.aspx)。
    大部分情况下,一个优良的写法是使用匿名函数,如下:

            int arg1 = 10;
            string arg2 = "argument temp";
            Thread t1 = new Thread(new ThreadStart(delegate
                {
                    MessageBox.Show(arg1.ToString() + arg2);
                }));

     以上的写法,仍然无法解决返回值的问题。如果要获取返回值的,则使用委托或包裹类等其它方法。但以上方法解决了参数的问题。

  

3:IsBackground

      必须注意IsBackground的问题,如果IsBackground为false的,则Windows程序在退出的时候,不会为你自动退出该线程。也就是实际上你的应用程序未结束。

4:异步调用中的参数和返回值

      能完美解决参数和返回值的是使用异步调用的方式。异步调用和Thread相比,一个最大的劣势是不能控制其优先级。
     首先,看代码:
     代码段1:

        public delegate string FuncHandle(int data1, int data2);
        FuncHandle fh ;
            
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            fh = new FuncHandle(this.Foo);
            AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl);
            fh.BeginInvoke(1, 3, callback, null);
        }

        public void AsyncCallbackImpl(IAsyncResult ar)   
        {
            string re = fh.EndInvoke(ar);
            MessageBox.Show(" " + ar.AsyncState);
        }   
  
        string Foo(int data1, int data2)   
        {   
            return " " + data1 + data2;   
        }  

     在异步调用中,如果想在异步的回调函数中,得到异步函数的返回值(如上面代码中的Foo函数的string返回值),则必须要在回调函数中使用EndInvoke(关于EndInvoke会在下文描述)。在上面的例子是如下这句。
     string re = fh.EndInvoke(ar);
     但是,有的时候fh并不见得是个类变量,这个时候,就需要我们将EndInvoke的执行主体由BeginInvoke传递进去。看修改过后的代码片段。
     代码段2:

        public delegate string FuncHandle(int data1, int data2);   
            
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            FuncHandle fh = new FuncHandle(this.Foo);
            AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl);
            fh.BeginInvoke(1, 3, callback, fh);

        }
        public void AsyncCallbackImpl(IAsyncResult ar)   
        {   
            FuncHandle dl = ar.AsyncState as FuncHandle;   
            string re = dl.EndInvoke(ar);
            MessageBox.Show(" " + ar.AsyncState);
        }   
  
        string Foo(int data1, int data2)   
        {   
            return "" + data1 + data2;   
        }  

     通过举一反三,其实BeginInvoke的最后一个参数,可以是任何对象,看具体的应用场景即可。
     下面再介绍一下EndInvoke。EndInvoke在回调函数中,用于承载执行的主体函数的返回值。在另外一个情况下,即上面的代码片段一个简化版本,如下:
     代码段3:

        public delegate string FuncHandle(int data1, int data2);   
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            FuncHandle fh = new FuncHandle(this.Foo);
            IAsyncResult ar = fh.BeginInvoke(1, 3, null, fh);
            string re = fh.EndInvoke(ar);
            MessageBox.Show(re);
        }
        
        string Foo(int data1, int data2)   
        {   
            return "" + data1 + data2;   
        }  

     我们可以看到,在这个代码片段中,我们根本没有使用回调函数,那么,我们就需要通过EndInvoke来阻滞主线程,使得返回函数主体的返回值。
     再多说一点,调用了 BeginInvoke 后,可以:
    1.进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。如上文的最后一个代码片段。
    2.使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用EndInvoke。这里主要是主程序等待异步方法,等待异步方法的结果。见代码段4。
    3.轮询由 BeginInvoke 返回的 IAsyncResult,IAsyncResult.IsCompeted确定异步调用何时完成,然后调用 EndInvoke。
    4.将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。这是在强制装换回调函数里面IAsyncResult.AsyncState(BeginInvoke方法的最后一个参数)成委托,然后用委托执行EndInvoke。即如上代码片段2。
    代码段4:

        public delegate string FuncHandle(int data1, int data2);
        string _sTemp = string.Empty;

        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            FuncHandle fh = new FuncHandle(this.Foo);
            AsyncCallback callback = new AsyncCallback(this.AsyncCallbackImpl);
            IAsyncResult ar = fh.BeginInvoke(1, 3, null, null);
            WaitHandle waitHandle = ar.AsyncWaitHandle;
            waitHandle.WaitOne();
            MessageBox.Show(_sTemp);
        }

        string Foo(int data1, int data2)   
        {
            Thread.Sleep(3000);
            string re = "" + data1 + data2;
            _sTemp = re;
            return re;
        }  
参考:http://www.cnblogs.com/peterzb/archive/2009/06/10/1500273.html
练习:

1.You are developing an application to perform mathematical calculations. You develop a class named     
CalculationValues. You write a procedure named PerformCalculation that operates on an instance of the class. You   
need to ensure that the user interface of the application continues to respond while calculations are being 
performed. You need to write a code segment that calls the PerformCalculation procedure to achieve this goal.    

Which code segment should you use? 
A. private void PerformCalculation() {...}   
private void DoWork()
{  CalculationValues myValues = new CalculationValues();  
Thread newThread = new Thread(       new ThreadStart(PerformCalculation));   
newThread.Start(myValues);}

B. private void PerformCalculation() {...}   
private void DoWork()
{  CalculationValues myValues = new CalculationValues();  
ThreadStart delStart = new        ThreadStart(PerformCalculation);  
Thread newThread = new Thread(delStart);
if (newThread.IsAlive) {newThread.Start(myValues);}} 
C. private void PerformCalculation (CalculationValues values) {...} 
private void DoWork()
{  CalculationValues myValues = new CalculationValues();  
Application.DoEvents();  PerformCalculation(myValues);  
Application.DoEvents();}
D. private void PerformCalculation(object values) {...}   
private void DoWork()
{  CalculationValues myValues = new CalculationValues();  
Thread newThread = new Thread(       new ParameterizedThreadStart(PerformCalculation));   
newThread.Start(myValues);}
Answer: D

2.You are developing an application that will perform mathematical calculations.  You need to ensure that the 
application is able to perform multiple calculations simultaneously. What should you do?     
A. Set the IdealProcessor property of the ProcessThread object.
B. Set the ProcessorAffinity property of the ProcessThread object.
C. For each calculation, call the QueueUserWorkItem method of the ThreadPool class. 
D. Set the Process.GetCurrentProcess().BasePriority property to High.
Answer: C

3.You are developing an application that will perform mathematical calculations.  You need to ensure that the 
application is able to perform multiple calculations simultaneously. What should you do?     
A. Set the IdealProcessor property of the ProcessThread object.
B. Set the ProcessorAffinity property of the ProcessThread object.
C. For each calculation, call the QueueUserWorkItem method of the ThreadPool class. 
D. Set the Process.GetCurrentProcess().BasePriority property to High.
Answer: C

4.Your application uses two threads, named threadOne and threadTwo.  You need to modify the code to prevent the execution of threadOne until threadTwo completes execution.   
What should you do?
A. Configure threadOne to run at a lower priority.
B. Configure threadTwo to run at a higher priority.
C. Use a WaitCallback delegate to synchronize the threads. 
D. Call the Sleep method of threadOne.
E. Call the SpinLock method of threadOne. 
Answer: C

NET C# 入门级.NET C# 专业级.NET 架构级BS系统专业级BS系统安全
1.开篇及C#程序、解决方案的结构
2.源码管理之TFS入门
3.打老鼠初级
……
21.CMS之主要功能实现
22.进程和线程基础
23.类型转换
24.算法基础
25.初级课程之剩余知识点
1.消灭打老鼠游戏中的自定义委托
2.垃圾回收
3.Dispose模式
……
16.异常使用指导
17.最常用的重构指导
18.Debug和IDE的进阶
19.Resharper的使用
20.ILSPY的使用
1.Socket入门
2.打造打老鼠游戏网络版
3.WCF入门
……
10.依赖注入
11.万物兼可测试
12.软件指标之覆盖率计算
13.软件指标之代码行
14.软件指标之圈复杂度、嵌套深度
1.HTML
2.WebForm原理
3.CSS必知必会
……
19.让浏览器缓存Shop
20.Asp.net的生命周期
21.Asp.net网站的发布以及调试晋级
22.BS程序的本质
23.压力测试我们的Shop
1.Fiddler必知必会
2.IE开发者工具必知必会
3.跨站脚本防范
4.权限欺骗防范
5.参数越界防范
6.会话劫持防范
7.CSRF防范
8.盗链防范
9.静态文件的保护


将本文分享到:QQ空间新浪微博人人网开心网搜狐微博MSN谷歌更多
 
 

免责声明:文章转载自《C#笔记19:多线程之线程启动、参数、返回值》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇WACV 2021 论文大盘点-图像分割篇SQL四种语言下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

在PC上调试微信手机页面的三种方法

场景 假设一个手机页面,开发者对其做了限制,导致只能在微信客户端中打开。而众所周知手机上非常不利于调试页面,所以需要能在电脑上打开并进行调试。这里针对常见的三种页面做一下分析,一一绕过其限制,(当然不要拿去干坏事) 工具准备 ‍‍‍‍1、方便调试的浏览器。个人喜欢Chrome,本文基于Chrome 43.0.2357.130 (正式版本) m (32 位)...

【ActiveMQ】消息重传机制

问题: 项目在修改consumer的确认签收机制从AUTO-ACK改为CLIENT-ACK模式,但在服务优雅停机并重启之后,发现若干数据被Pending后未被重发。 过段时间再一次停启服务后,Pending的数据才能被消费成功。 此问题在数据量大时基本可以复现。 类似问题: https://stackoverflow.com/questions/54074...

Win7 计算机(我的电脑)右键菜单“管理”打不开,解决方法

Win7 计算机(我的电脑)右键菜单“管理”打不开   自从重返校园之后,每天都很多事情要忙,时间被分割成碎片,写博客的念头随之消失了。今天遇到了电脑的管理打不开了,解决方法如下: WIN7计算机(我的电脑)右键“管理”打不开,弹出与之关联的程序找不到,显示错误。这是由于系统默认路径被修改,比如我的文档路径转移到其他分区上,也同样会出现这种情况。下面可以有...

ThinkPHP6 核心分析:系统服务

什么是系统服务?系统服务是对于程序要用到的类在使用前先进行类的标识的绑定,以便容器能够对其进行解析(通过服务类的 register 方法),还有就是初始化一些参数、注册路由等(不限于这些操作,主要是看一个类在使用之前的需要,进行一些配置,使用的是服务类的 boot 方法)。以下面要介绍到的 ModelService 为例,ModelService类提供服务...

TypeScript 中slice(-1)是什么意思?

slice(start,end)方法提取字符串的一部分并返回一个新字符串。 使用方法 一般来说该方法有两个参数,使用方法如下:slice(start,end)    start表示要提取的片段的起始下标,end表示提取片段最后一个字符的后一个字符的下标; 1.两个参数都为正数 var str="Hello happy world!" document.wr...

Jmeter JAVA请求入门

一、Jmeter完成一个java请求实现方法 两种实现方式: 实现JavaSamplerClient接口 继承AbstractJavaSamplerClient抽象类 二、使用AbstractJavaSamplerClient抽象类编写java程序 1、核心步骤 1)创建一个Maven工程; 2)本地Maven库路径确认,添加pom.xml内容,编写依赖的...