【转】.NET多线程编程(14)—— 多线程的自动管理
在多线程中经常会出现两种情况:
一种情况: 应用中线程把大部分时间花费在等待状态等待某个事件发生然后才能给予响应,这般使用ThreadPool(线程池)来解决;
另种情况:线程平时都处于休眠状态只是周期性地被唤醒,这一般使用Timer(定时器)来解决;
ThreadPool类提供个由系统维护线程池(可以看作个线程容器)该容器需要 Windows 2000 以上系统支持其中某些思路方法了只有高版本Windows才有API
将线程安放在线程池里需使用ThreadPool.QueueUserWorkItem思路方法该思路方法原型如下:
//将个线程放进线程池该线程Start思路方法将WaitCallback代理对象代表
public bool QueueUserWorkItem(WaitCallback);
//重载思路方法如下参数object将传递给WaitCallback所代表思路方法
public bool QueueUserWorkItem(WaitCallback, object);
注意:
ThreadPool类是个静态类你不能也不必要生成它对象而且旦使用该思路方法在线程池中添加了个项目那么该项目将是无法取消
在这里你无需自己建立线程只需把你要做工作写成然后作为参数传递给
ThreadPool.QueueUserWorkItem思路方法就行了传递思路方法就是依靠WaitCallback代理对象而线程建立、管理、运行等工作都是由系统自动完成你无须考虑那些复杂细节问题
ThreadPool 使用方法:
首先创建了个ManualReEvent对象该对象就像个信号灯可以利用它信号来通知其它线程
一种情况: 应用中线程把大部分时间花费在等待状态等待某个事件发生然后才能给予响应,这般使用ThreadPool(线程池)来解决;
另种情况:线程平时都处于休眠状态只是周期性地被唤醒,这一般使用Timer(定时器)来解决;
ThreadPool类提供个由系统维护线程池(可以看作个线程容器)该容器需要 Windows 2000 以上系统支持其中某些思路方法了只有高版本Windows才有API
将线程安放在线程池里需使用ThreadPool.QueueUserWorkItem思路方法该思路方法原型如下:
//将个线程放进线程池该线程Start思路方法将WaitCallback代理对象代表
public bool QueueUserWorkItem(WaitCallback);
//重载思路方法如下参数object将传递给WaitCallback所代表思路方法
public bool QueueUserWorkItem(WaitCallback, object);
注意:
ThreadPool类是个静态类你不能也不必要生成它对象而且旦使用该思路方法在线程池中添加了个项目那么该项目将是无法取消
在这里你无需自己建立线程只需把你要做工作写成然后作为参数传递给
ThreadPool.QueueUserWorkItem思路方法就行了传递思路方法就是依靠WaitCallback代理对象而线程建立、管理、运行等工作都是由系统自动完成你无须考虑那些复杂细节问题
ThreadPool 使用方法:
首先创建了个ManualReEvent对象该对象就像个信号灯可以利用它信号来通知其它线程
本例中当线程池中所有线程工作都完成以后ManualReEvent对象将被设置为有信号从而通知主线程继续运行
ManualReEvent对象有几个重要思路方法:
化该对象时用户可以指定其默认状态(有信号/无信号);
在化以后该对象将保持原来状态不变直到它Re或者Set思路方法被:
Re思路方法:将其设置为无信号状态;
Set思路方法:将其设置为有信号状态
WaitOne思路方法:使当前线程挂起直到ManualReEvent对象处于有信号状态此时该线程将被激活然后将向线程池中添加工作项这些以形式提供工作项被系统用来化自动建立线程当所有线程都运行完了以后ManualReEvent.Set思路方法被了ManualReEvent.WaitOne思路方法而处在等待状态主线程将接收到这个信号于是它接着往下执行完成后边工作
ThreadPool 使用方法举例:
using;
using.Collections;
using.Threading;
ThreadExample
{
//这是用来保存信息数据结构将作为参数被传递
publicSomeState
{
publicCookie;
publicSomeState(iCookie)
{
Cookie=iCookie;
}
}
publicAlpha
{
publicHashtableHashCount;
publicManualReEventeventX;
publiciCount=0;
publiciMaxCount=0;
publicAlpha(MaxCount)
{
HashCount=Hashtable(MaxCount);
iMaxCount=MaxCount;
}
//线程池里线程将Beta思路方法
publicvoidBeta(Objectstate)
{
//输出当前线程hash编码值和Cookie值
Console.WriteLine("{0}{1}:",Thread.CurrentThread.GetHashCode,((SomeState)state).Cookie);
Console.WriteLine("HashCount.Count{0},Thread.CurrentThread.GetHashCode{1}",HashCount.Count,Th
read.CurrentThread.GetHashCode);
lock(HashCount)
{
//如果当前Hash表中没有当前线程Hash值则添加的
(!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode))
HashCount.Add(Thread.CurrentThread.GetHashCode,0);
HashCount[Thread.CurrentThread.GetHashCode]=
(()HashCount[Thread.CurrentThread.GetHashCode])+1;
}
iX=2000;
Thread.Sleep(iX);
//Interlocked.Increment操作是个原子操作具体请看下面介绍说明
Interlocked.Increment(refiCount);
(iCountiMaxCount)
{
Console.WriteLine;
Console.WriteLine("SettingeventX");
eventX.Set;
}
}
}
publicSimplePool
{
publicMain(args)
{
Console.WriteLine("ThreadPoolSample:");
boolW2K=false;
MaxCount=10;//允许线程池中运行最多10个线程
//新建ManualReEvent对象并且化为无信号状态
ManualReEventeventX=ManualReEvent(false);
Console.WriteLine("Queuing{0}itemstoThreadPool",MaxCount);
AlphaoAlpha=Alpha(MaxCount);
//创建工作项
//注意化oAlpha对象eventX属性
oAlpha.eventX=eventX;
Console.WriteLine("QueuetoThreadPool0");
try
{
//将工作项装入线程池
//这里要用到Windows2000以上版本才有API所以可能出现NotSupportException异常
ThreadPool.QueueUserWorkItem(WaitCallback(oAlpha.Beta),SomeState(0));
W2K=true;
}
catch(NotSupportedException)
{
Console.WriteLine("TheseAPI'smayfailwhencalledonanon-
Windows2000system.");
W2K=false;
}
(W2K)//如果当前系统支持ThreadPool思路方法.
{
for(iItem=1;iItem<MaxCount;iItem)
{
//插入队列元素
Console.WriteLine("QueuetoThreadPool{0}",iItem);
ThreadPool.QueueUserWorkItem(WaitCallback(oAlpha.Beta),SomeState(iItem));
}
Console.WriteLine("WaitingforThreadPooltodrain");
//等待事件完成即线程ManualReEvent.Set思路方法
eventX.WaitOne(Timeout.Infinite,true);
//WaitOne思路方法使它线程等待直到eventX.Set思路方法被
Console.WriteLine("ThreadPoolhasbeendrained(Eventfired)");
Console.WriteLine;
Console.WriteLine("Loadacrossthreads");
foreach(objectoinoAlpha.HashCount.Keys)
Console.WriteLine("{0}{1}",o,oAlpha.HashCount[o]);
}
Console.ReadLine;
0;
}
}
}
}
中应该引起注意地方:
SomeState类是个保存信息数据结构它在中作为参数被传递给每个线程你需要把些有用信息封装起来提供
给线程而这种方式是非常有效
出现InterLocked类也是专为多线程而存在它提供了些有用原子操作
原子操作:就是在多线程中如果这个线程这个操作修改个变量那么其他线程就不能修改这个变量了这跟lock关键字在本质上是样
输出结果:
ThreadPoolSample:
Queuing10itemstoThreadPool
QueuetoThreadPool0
QueuetoThreadPool1
QueuetoThreadPool2
QueuetoThreadPool3
QueuetoThreadPool4
QueuetoThreadPool5
20:
HashCount.Count0,Thread.CurrentThread.GetHashCode2
QueuetoThreadPool6
QueuetoThreadPool7
QueuetoThreadPool8
QueuetoThreadPool9
WaitingforThreadPooltodrain
41:
HashCount.Count1,Thread.CurrentThread.GetHashCode4
62:
HashCount.Count1,Thread.CurrentThread.GetHashCode6
73:
HashCount.Count1,Thread.CurrentThread.GetHashCode7
24:
HashCount.Count1,Thread.CurrentThread.GetHashCode2
85:
HashCount.Count2,Thread.CurrentThread.GetHashCode8
96:
HashCount.Count2,Thread.CurrentThread.GetHashCode9
107:
HashCount.Count2,Thread.CurrentThread.GetHashCode10
118:
HashCount.Count2,Thread.CurrentThread.GetHashCode11
49:
HashCount.Count2,Thread.CurrentThread.GetHashCode4
SettingeventX
ThreadPoolhasbeendrained(Eventfired)
Loadacrossthreads
111
101
91
81
71
61
42
22
我们应该彻底地分析上面把握住线程池本质理解它存在意义是什么这样才能得心应手地使用它
ManualReEvent对象有几个重要思路方法:
化该对象时用户可以指定其默认状态(有信号/无信号);
在化以后该对象将保持原来状态不变直到它Re或者Set思路方法被:
Re思路方法:将其设置为无信号状态;
Set思路方法:将其设置为有信号状态
WaitOne思路方法:使当前线程挂起直到ManualReEvent对象处于有信号状态此时该线程将被激活然后将向线程池中添加工作项这些以形式提供工作项被系统用来化自动建立线程当所有线程都运行完了以后ManualReEvent.Set思路方法被了ManualReEvent.WaitOne思路方法而处在等待状态主线程将接收到这个信号于是它接着往下执行完成后边工作
ThreadPool 使用方法举例:
using;
using.Collections;
using.Threading;
ThreadExample
{
//这是用来保存信息数据结构将作为参数被传递
publicSomeState
{
publicCookie;
publicSomeState(iCookie)
{
Cookie=iCookie;
}
}
publicAlpha
{
publicHashtableHashCount;
publicManualReEventeventX;
publiciCount=0;
publiciMaxCount=0;
publicAlpha(MaxCount)
{
HashCount=Hashtable(MaxCount);
iMaxCount=MaxCount;
}
//线程池里线程将Beta思路方法
publicvoidBeta(Objectstate)
{
//输出当前线程hash编码值和Cookie值
Console.WriteLine("{0}{1}:",Thread.CurrentThread.GetHashCode,((SomeState)state).Cookie);
Console.WriteLine("HashCount.Count{0},Thread.CurrentThread.GetHashCode{1}",HashCount.Count,Th
read.CurrentThread.GetHashCode);
lock(HashCount)
{
//如果当前Hash表中没有当前线程Hash值则添加的
(!HashCount.ContainsKey(Thread.CurrentThread.GetHashCode))
HashCount.Add(Thread.CurrentThread.GetHashCode,0);
HashCount[Thread.CurrentThread.GetHashCode]=
(()HashCount[Thread.CurrentThread.GetHashCode])+1;
}
iX=2000;
Thread.Sleep(iX);
//Interlocked.Increment操作是个原子操作具体请看下面介绍说明
Interlocked.Increment(refiCount);
(iCountiMaxCount)
{
Console.WriteLine;
Console.WriteLine("SettingeventX");
eventX.Set;
}
}
}
publicSimplePool
{
publicMain(args)
{
Console.WriteLine("ThreadPoolSample:");
boolW2K=false;
MaxCount=10;//允许线程池中运行最多10个线程
//新建ManualReEvent对象并且化为无信号状态
ManualReEventeventX=ManualReEvent(false);
Console.WriteLine("Queuing{0}itemstoThreadPool",MaxCount);
AlphaoAlpha=Alpha(MaxCount);
//创建工作项
//注意化oAlpha对象eventX属性
oAlpha.eventX=eventX;
Console.WriteLine("QueuetoThreadPool0");
try
{
//将工作项装入线程池
//这里要用到Windows2000以上版本才有API所以可能出现NotSupportException异常
ThreadPool.QueueUserWorkItem(WaitCallback(oAlpha.Beta),SomeState(0));
W2K=true;
}
catch(NotSupportedException)
{
Console.WriteLine("TheseAPI'smayfailwhencalledonanon-
Windows2000system.");
W2K=false;
}
(W2K)//如果当前系统支持ThreadPool思路方法.
{
for(iItem=1;iItem<MaxCount;iItem)
{
//插入队列元素
Console.WriteLine("QueuetoThreadPool{0}",iItem);
ThreadPool.QueueUserWorkItem(WaitCallback(oAlpha.Beta),SomeState(iItem));
}
Console.WriteLine("WaitingforThreadPooltodrain");
//等待事件完成即线程ManualReEvent.Set思路方法
eventX.WaitOne(Timeout.Infinite,true);
//WaitOne思路方法使它线程等待直到eventX.Set思路方法被
Console.WriteLine("ThreadPoolhasbeendrained(Eventfired)");
Console.WriteLine;
Console.WriteLine("Loadacrossthreads");
foreach(objectoinoAlpha.HashCount.Keys)
Console.WriteLine("{0}{1}",o,oAlpha.HashCount[o]);
}
Console.ReadLine;
0;
}
}
}
}
中应该引起注意地方:
SomeState类是个保存信息数据结构它在中作为参数被传递给每个线程你需要把些有用信息封装起来提供
给线程而这种方式是非常有效
出现InterLocked类也是专为多线程而存在它提供了些有用原子操作
原子操作:就是在多线程中如果这个线程这个操作修改个变量那么其他线程就不能修改这个变量了这跟lock关键字在本质上是样
输出结果:
ThreadPoolSample:
Queuing10itemstoThreadPool
QueuetoThreadPool0
QueuetoThreadPool1
QueuetoThreadPool2
QueuetoThreadPool3
QueuetoThreadPool4
QueuetoThreadPool5
20:
HashCount.Count0,Thread.CurrentThread.GetHashCode2
QueuetoThreadPool6
QueuetoThreadPool7
QueuetoThreadPool8
QueuetoThreadPool9
WaitingforThreadPooltodrain
41:
HashCount.Count1,Thread.CurrentThread.GetHashCode4
62:
HashCount.Count1,Thread.CurrentThread.GetHashCode6
73:
HashCount.Count1,Thread.CurrentThread.GetHashCode7
24:
HashCount.Count1,Thread.CurrentThread.GetHashCode2
85:
HashCount.Count2,Thread.CurrentThread.GetHashCode8
96:
HashCount.Count2,Thread.CurrentThread.GetHashCode9
107:
HashCount.Count2,Thread.CurrentThread.GetHashCode10
118:
HashCount.Count2,Thread.CurrentThread.GetHashCode11
49:
HashCount.Count2,Thread.CurrentThread.GetHashCode4
SettingeventX
ThreadPoolhasbeendrained(Eventfired)
Loadacrossthreads
111
101
91
81
71
61
42
22
我们应该彻底地分析上面把握住线程池本质理解它存在意义是什么这样才能得心应手地使用它
本贴子以“现状”提供且没有任何担保,同时也没有授予任何权利
This posting is provided "AS IS" with no warranties, and confers no rights.
This posting is provided "AS IS" with no warranties, and confers no rights.
浙公网安备 33010602011771号