回顾
1. 线程分前台线程和后台线程,差别就在于是否会阻止主线程结束
2. 线程异步是多线程同步执行,线程同步是在多线程遇到抢夺资源的时候防止多个线程打架
3. 实例化Thread类的时候可以使用的委托有两个,分别是有参数 和 无参数
4. 几个同样的线程,如果希望被优先执行,则需要为其设置优先级
5. 暂停线程有堵塞,挂起,join等方式。
主要内容
1. 线程通知机制
AutoResetEvent是线程实现通知操作的重要方法。通常,AutoResetEvent用于通知正在等待线程已发生事件,允许线程通过发信号互相通信。
AutoResetEvent事件对象提供给了我们这样的通知机制,让我们可以控制线程执行的先后顺序,它的常用方法如下:
1. set:设置并发送信号
2. Reset:重置信号,也就是使信号无效
3. WaitOne:等待一个信号,如果没有信号到来则等待
4. WaitAny:静态方法,等待一个信号数组,信号数组里面有任何信号到都可以,否则等待。
5. WaitAll: 静态方法,等待一个信号数组,信号数组里的信号全部到齐才可以,否则等待。
创建一个AutoResetEvent对象,构造方法里需要带一个bool型参数,如:
AutoResetEvent myResetEvent=new AutoResetEvent(false);
这个参数如果是false表示事件开始是无信号状态,当参数为true表示创建的事件开始有信号的,就相当于使用false参数创建事件后即调用了set方法。
2. 线程通信实践
1. 先写后读
2. 美好人生
3. 异步委托
1. IAsyncResult
2. 等待句柄
3. 异步回调
有关这些个线程的学习,我也成了牵线木偶了,跟着练习做的,迷糊着就过来了,教程看了两三遍,知道了AutoResetEvent类是线程间通信中目前所知道的唯一的类,它的方法也不多,等待1个或多个信号的,发送信息的就一个set方法,接收又分实例和静态方法,一次接收多个信息的是AutoResetEvent数组等等。
线程异步操作就一个IAsyncResult这个接口,在这里用到了委托来携带方法,如果直接使用方法是不行的,我测试过了。同时如果想使用异步回调这个参数,那么第四个参数也是少不了的,因需要在异步回调中的收尾工作还需要这个委托来调用EndInvoke呢。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Con433
{
//定义一个委托用来携带方法
public delegate int delegateDajiangyou(object o,int ms);
class Program
{
public static int Dajiangyou(object o, int ms)
{
Thread t = Thread.CurrentThread;
t.Name = "便利店";
Console.WriteLine("\n小明的妈妈给了小明{0}元钱,让小明到{1}打酱油!让他在{2}秒时间里多打几瓶回家\n",o,t.Name,ms);
Thread.Sleep(ms);//打酱油过程中
return (int)o / 20;
}
//异步回调函数
public static void asyncCallBack(IAsyncResult ia)
{
//先判断接口对象是否为空,为空则抛出异常
if (ia == null)
throw new ArgumentNullException("ia");
//将异步状态接口对象中的对象参数转换成委托类型,即是IsyncReult中的第四个参数
delegateDajiangyou dd = ia.AsyncState as delegateDajiangyou;
//使用代码追踪器,监测对象
System.Diagnostics.Trace.Assert(dd != null, "无效的对象");
//从异步状态收尾的方法中获取,异步状态开始调用的委托方法的执行结果或返回值
//没有IsyncResult中的第四个参数,dd将为空,即下面这一句将不被执行
int result = dd.EndInvoke(ia);
Console.WriteLine("\n小明的妈妈很高兴自己有个乖儿子,看了看小打回来的{0}瓶酱油,继续做饭!\n", result);
}
/// <summary>
/// 主函数入口
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Thread t = Thread.CurrentThread;
t.Name = "家里";
Console.WriteLine("\n小明在{0},妈妈做饭木酱油了,且酱油用的太快,但小明懒,妈妈说回来给零花钱,小明很高兴。"+
"\n可妈妈但心小明半路玩耍耽误事,说,如果在规定的时间里回不来就从零花钱里扣除,迟到1000s,扣一块!",t.Name);
delegateDajiangyou xiaoming = Dajiangyou;
int ms=4000*new Random().Next(3);
//IAsyncResult类是表示异步操作状态,返回操作状态
//如果要使用第三个参数,则此语句以下的部分先进行注释
//实话,我也没怎么明白透这些类的具体的详细作用
//IAsyncResult ir = xiaoming.BeginInvoke(50, ms, null, null);
//第四个参数可以是任意对象,以便在异步回调函数中使用它
IAsyncResult ir = xiaoming.BeginInvoke(50, ms, asyncCallBack, xiaoming);
#region 使用异步回调参数时需要注释的部分
//Thread.Sleep(4000);
//int i = 0;//如果超过规定的时间,就开始扣钱
//if (ir.IsCompleted)
//{
// Console.WriteLine("小明真妈妈心中听话的乖孩子,零花不要随便花,留着以后买铅笔!乖。。。");
//}
//else
//{
// while (!ir.IsCompleted)
// {
// i++;
// Console.WriteLine("{0}块钱没了", i);
// //特别情况下,追加了这段代码
// if (ir.AsyncWaitHandle.WaitOne(100, false))
// {
// //1000ms设定的是等待的条件,true/false是否在等待之前
// Console.WriteLine("到现在还没把酱油买回来,这熊孩纸是不是又在路边玩起来,算了还是洗洗手出去找他回来吧!");
// break;//停扣费,中断循环。
// }
// //Thread.Sleep(1000);
// }
//}
//int result = xiaoming.EndInvoke(ir);//结束监测状态,返回方法执行的结果
//if (i > 0)
//{
// Console.WriteLine("明明,你迟到了{0}秒钟,妈妈要算了一下,要从你所得的零花钱里扣除{1}块钱", i * 1000, i);
//}
//else
//{
// Console.WriteLine("小明的妈妈很高兴自己有个乖儿子,看了看小打回来的{0}瓶酱油,继续做饭!", result);
//}
#endregion
Console.ReadKey();
}
}
}
为了以后在做实例 或 项目中能有据可查,我把自己学到的,做的练习都贴上来了。个人见解的旁白,只代表个人的意见。建议无论是砖家还是叫兽说的话都不要全信,还是实例一下好些,实践出真知吗!
以下补充的是线程通信的简单实例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Con43
{
class Program
{
static AutoResetEvent ar = new AutoResetEvent(false);//线程通信必须的一个类
static int num;
static void Main(string[] args)
{
//线程通信之读写
Thread t = Thread.CurrentThread;//获取当前线程
t.Name = "写线程";
Thread t2 = new Thread(Rthread);//读线程
t2.Start();
for (int i = 0; i < 20; i++)
{
num = i;
Console.WriteLine("当前线程为:{0},发送值:{1}", t.Name, num);
ar.Set();//发送信号,实例方法
//尽管我用了锁,但如果没这1毫秒的阻塞,还是会出乱子
Thread.Sleep(1);//等读
}
t2.Abort();//终止读线程
Console.ReadKey();
}
public static void Rthread()
{
//读线程
Thread t = Thread.CurrentThread;
t.Name = "读线程";
while (true)//此线程一直在等待接收信息
{
lock (ar)
{
ar.WaitOne();//等待一个信号,实例方法
Console.WriteLine("{0},接收到的值是:{1}", t.Name, num);
Thread.Sleep(1);//等写
}
}
}
}
}
还有一个:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Con432
{
class Program
{
static void Main(string[] args)
{
person p = new person();
Thread[] array = {
new Thread(p.che),
new Thread(p.fang),
new Thread(p.wife)
};
foreach (Thread t in array)
{
t.Start();
}
if (AutoResetEvent.WaitAll(p.ar))
{
p.CGR();
}
Console.ReadKey();
}
}
/// <summary>
/// 我们人类奋斗的目标,车房媳妇,老师有心了
/// 哈哈。。。
/// </summary>
public class person
{
public AutoResetEvent[] ar;
public person()
{
ar = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};
}
public void che()
{
ar[0].Set();
Console.WriteLine("车子有了!");
}
public void fang()
{
ar[1].Set();
Console.WriteLine("房子有了!");
}
public void wife()
{
ar[2].Set();
Console.WriteLine("媳妇有了!");
}
public void CGR()
{
Console.WriteLine("我也是成功人士了,哈哈。。。");
}
}
}