??xml version="1.0" encoding="utf-8" standalone="yes"?>
在很多用C++开发服务器产品Ӟ需要将不同的数据类型存储到一个容器中(有点cMHttpSession可以保存?x)话期间Lcd的数?Q供其它使用E序查找?br> 在Java和C#中这是一个简单的问题Q可以用Object对象来实现类型无关的数据l构Qƈ且很好的解决?jin)内存回收等问题?br> 但C++中很隑ց到这一点,C++是一门静(rn)态类型语aQ没有一个所有类型的基类?/p>
2.一般方?/strong>
一般解册个问题的办法是用void*指针来存储数据,象下面的代码Q?br> map<string,void*>
但是q样带来几个问题Q?br> Q?Q因为C++在不知道cȝ型时无法正确的释攑ֆ存;
Q?Q很多用者用它Ӟ释放内存的时机难于确定;
3.让它正确释放内存
我们可以定义一个公q基类Q让所有需要放到容器的cdl承?br> class Object
{
public:
virtual ~Object(){cout<<"Object Destroy" << endl;}
};
׃使用?jin)virtual析构函数因此可以保delete obj的时可以正常工作。因此上面的容器定义变成?jin)这P(x)
map<string,Object*>
4.让它知道何时释放内存
大家都知道,q时必须使用引用计数Q不q很q运有现成的Q我们用boost::share_ptr
map<string,boost::share_ptr<Object*> >
很好两个问题都已l解冻I但如何向他们中加入C++的基本类型呢Q?/p>
5.开发基本类型的装c?/strong>
基本cd很多Q如果每一个都写一个类Q太累了(jin)Q我们可以定义一个模板,q里的难Ҏ(gu)基本cd之间的操作符重蝲Q不同类型之间的q算q回的类型ƈ不相同,q就需要写很多重蝲函数Q在q里我们使用Loki来简化这些操作。用Loki的TypeList来自动计应该是什么返回?br> #include"Typelist.h" //Loki头文?br> template <typename T>
class PrimerType:public Object
{
public:
typedef T value_type;//基本cd
typedef PrimerType<T> class_type;//基本cd的对象类?br>
public:
PrimerType()
:m_value((value_type)0)
{
}
template<typename Other>
PrimerType(const Other& value)
:m_value(value)
{
}
~PrimerType()
{
cout<<"PrimerType Destroy" << endl;
}
//基本cd转换操作W重?br> operator value_type() const
{
return m_value;
}
//赋值操作符重蝲
const class_type& operator=(value_type value)
{
m_value=value;
return *this;
}
bool operator!( ) const
{
return !m_value;
}
//作ؓ(f)cL员的术q算W操作符重蝲
class_type& operator++()
{// ++ 前缀
m_value+=1;
return *this;
}
const class_type operator++(int)
{// ++ 后缀
class_type oldValue=*this;
m_value+=1;
return oldValue;
}
class_type& operator--()
{// -- 前缀
m_value-=1;
return *this;
}
const class_type operator--(int)
{// -- 后缀
class_type oldValue=*this;
m_value-=1;
return oldValue;
}
class_type& operator+=(const value_type& value)
{
m_value+=value;
return *this;
}
//。。。省?= /= *= &= |= ^= %= {等
private:
value_type m_value;
friend istream& operator>><T> ( istream& is, class_type& ptvalue );
};
//输入函敎ͼ不用输出Q通过cd操作W重载自动完成)(j)
template<typename T>
istream& operator>> ( istream& is, PrimerType<T>& ptvalue )
{
is >> ptvalue.m_value;
return is;
}
//基本cd重定?br> typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef __int64 int64;
typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
//基本cd的对象类?br> typedef PrimerType<bool> Boolean;
typedef PrimerType<int8> Int8;
typedef PrimerType<int16> Int16;
typedef PrimerType<int32> Int32;
typedef PrimerType<int64> Int64;
typedef PrimerType<uint8> UInt8;
typedef PrimerType<uint16> UInt16;
typedef PrimerType<uint32> UInt32;
typedef PrimerType<uint64> UInt64;
typedef PrimerType<float> Float;
typedef PrimerType<double> Double;
typedef PrimerType<long> Long;
typedef PrimerType<unsigned long> ULong;
//更友好的名字
typedef Int8 Char;
typedef Int16 Short;
typedef Int32 Int;
typedef UInt8 Byte;
typedef UInt16 UShort;
typedef UInt32 UInt;
//术q算q回cd的traitsQ运时以排在后面的cdq回
#define PRIMERTYPELIST TYPELIST_13(bool,int8,uint8,int16,uint16,int32,uint32,long,unsigned long,int64,uint64,float,double)
// |
// int
template <typename T1, typename T2>
struct ResultType_Traits
{
enum { lefttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T1>::value};
enum { righttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T2>::value};
enum { resulttype_index = (lefttype_index>righttype_index)?lefttype_index:righttype_index};
typedef typename ::Loki::TL::TypeAt<PRIMERTYPELIST, (resulttype_index<5)?5:resulttype_index >::Result result_type;
};
//作ؓ(f)全局的算术运符操作W重?+ - * /
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const PrimerType<T1>& lhs,const T2& rhs)
{
return (T1)lhs+rhs;
}
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const T1& lhs,const PrimerType<T2>& rhs)
{
return lhs+(T2)rhs;
}
template<typename T1,typename T2>
typename ResultType_Traits<T1,T2>::result_type operator +(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)
{
return (T1)lhs+(T2)rhs;
}
//。。。省?- * /{等
// 逻辑q算W重?br> template<typename T1,typename T2>
bool operator ==(const PrimerType<T1>& lhs,const T2& rhs)
{
return (T1)lhs==rhs;
}
template<typename T1,typename T2>
bool operator ==(const T1& lhs,const PrimerType<T2>& rhs)
{
return lhs==(T2)rhs;
}
template<typename T1,typename T2>
bool operator ==(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)
{
return (T1)lhs==(T2)rhs;
}
//。。。省?!= >= {等
6.结
使用对象来表C基本类型,׃使用?jin)virtual的析构它是有内存?gu)费的,但在很多应用中它是很有用的?br> 同时你可以增加String/DateTime的特化支持,q样完整了(jin)
]]>
public
void ThreadProc();
Thread thread = new Thread( new ThreadStart( ThreadProc ) );
thread.IsBackground = true;
thread.Start();
但是很多时候,在新的线E中Q我们需要与 UI q行交互Q在 .net 中不允许我们直接q样做。可以参?/span> MSDN 中的描述Q?/span>
“Windows
H体?/span>使用单线E单?span lang="EN-US"> (STA) 模型Q因?span lang="EN-US">“Windows H体?/span>Z本机 Win32 H口Q?span lang="EN-US"> Win32 H口从本质上而言是单元线E?span lang="EN-US">STA 模型意味着可以在Q何线E上创徏H口Q但H口一旦创建后׃能切换线E,q且对它的所有函数调用都必须在其创徏U程上发生。除?span lang="EN-US"> Windows H体之外Q?span lang="EN-US">.NET Framework 中的cM用自qE模型?span lang="EN-US">
STA
模型要求需从控件的非创建线E调用的控g上的MҎ(gu)必须被封送到Q在其上执行Q该控g的创建线E。基c?span lang="EN-US"> Control 为此目的提供?jin)若q方法(Invoke?span lang="EN-US">BeginInvoke ?span lang="EN-US"> EndInvokeQ?b>Invoke生成同步Ҏ(gu)调用Q?b>BeginInvoke生成异步Ҏ(gu)调用?span lang="EN-US">
Windows
H体中的控g被绑定到特定的线E,不具备线E安全性。因此,如果从另一个线E调用控件的Ҏ(gu)Q那么必M用控件的一?span lang="EN-US"> Invoke Ҏ(gu)来将调用送到适当的线E?span lang="EN-US">
正如所看到的,我们必须调用 Invoke Ҏ(gu)Q?/span> BeginInvoke 可以认ؓ(f)?/span> Invoke 的异步版本。调用方法如下:(x)
public
delegate
void OutDelegate(string text);
public
void OutText(string text)
{
txt.AppendText(text);
txt.AppendText( "\t\n" );
}
OutDelegate outdelegate = new OutDelegate( OutText );
this
.BeginInvoke(outdelegate, newobject[]{text});
如果我们需要在另外一个线E里面对 UI q行操作Q我们需要一个类?/span> OutText 的函敎ͼq需要一个该函数的委?/span> delegate Q当?dng)q里展示的是自定义的Q?/span> .net 中还有很多其他类型的委托Q可以直接用,不需要而外声明。例如:(x) MethodInvoker ?/span> EventHandler Q这两种cd委托的函数外观是固定的, MethodInvoker ?/span> void Function() cd的委托,?/span> EventHandler ?/span> void Function(object, EventArgs) cd的委托,W一个不支持参数Q第二中的参数类型和数量都是固定的,q两U委托可以很方便的调用,但是~Z灉|性。请注意 BeginInvoke 前面的对象是 this Q也是ȝE。现在再介绍 Control.InvokeRequired Q?/span> Control 是所有控件的基类Q对于这个属?/span> MSDN 的描q是Q?/span>
获取一个|该值指C用方在对控gq行Ҏ(gu)调用时是否必调?/span>
Invoke
Ҏ(gu)Q因用方位于创徏控g所在的U程以外的线E中?/span>
该属性可用于定是否必须调用
Invoke
Ҏ(gu)Q当不知道什么线E拥有控件时q很有用?/span>
也就是说通过判断 InvokeRequired 可以知道是否需要用委托来调用当前控件的一些方法,如此可以?/span> OutText 函数修改一下:(x)
public
delegate
void OutDelegate(string text);
public
void OutText(string text)
{
if( txt.InvokeRequired )
{
OutDelegate outdelegate = new OutDelegate( OutText );
this.BeginInvoke(outdelegate, newobject[]{text});
return;
}
txt.AppendText(text);
txt.AppendText( "\t\n" );
}
注意Q这里的函数没有q回Q如果有q回Q需要调?/span> Invoke 或?/span> EndInvoke 来获得返回的l果Q不要因为包装而丢׃(jin)q回倹{如果调用没有完成, Invoke ?/span> EndInvoke 都将?x)引起阻塞?/span>
现在如果我有一个线E函数如下:(x)
public
void ThreadProc()
{
for(int i = 0; i < 5; i++)
{
OutText( i.ToString() );
Thread.Sleep(1000);
}
}
如果循环的次数很大,或者漏?/span> Thread.Sleep(1000); Q那么你?/span> UI 肯定?x)停止响应,想知道原因吗Q看?/span> BeginInvoke 前面的对象,没错Q就?/span> this Q也是ȝE,当你的主U程不停的调?/span> OutText 的时候, UI 当然?x)停止响应?/span>
与以?/span>
VC
中创Z个新的线E需要调?/span>
AfxBeginThread
函数Q该函数中第一个参数就是线E函数的地址Q而第二个参数是一个类型ؓ(f)
LPVOID
的指针类型,q个参数传递给U程函数。现在我们没有办法再使用q种Ҏ(gu)来传递参C(jin)。我们需要将传递给U程的参数和U程函数包装成一个单独的c,然后在这个类的构造函C初始化该U程所需的参敎ͼ然后再将该实例的U程函数传递给
Thread
cȝ构造函数。代码大致如下:(x)
public
class ProcClass
{
private
string procParameter = "";
public ProcClass(string parameter)
{
procParameter = parameter;
}
public
void ThreadProc()
{
}
}
ProcClass threadProc = new ProcClass("use thread class");
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
是q样Q需要徏立一个中间类来传递线E所需的参数?/span>
那么如果我的U程又需要参敎ͼ又需要和 UI q行交互的时候该怎么办呢Q可以修改一下代码:(x)
public
class ProcClass
{
private
string procParameter = "";
private Form1.OutDelegate delg = null;
public ProcClass(string parameter, Form1.OutDelegate delg)
{
procParameter = parameter;
this.delg = delg;
}
public
void ThreadProc()
{
delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);
}
}
ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));
Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );
thread.IsBackground = true;
thread.Start();
q里只是我的一些理解,如果有什么错误或者不当的地方Q欢q指出?/span>
public void afunction(object o)
{
// do what ever the function is supposed to do.
}
//thread entry code
{
// create an instance of WaitCallback
WaitCallback myCallback = new WaitCallback (afunction);
//add this to the thread pool / queue a task
ThreadPool.QueueUserWorkItem (myCallback);
}
你也可以通过调用ThreadPool.RegisterWaitForSingleObjectҎ(gu)来传递一个System.Threading.WaitHandle,当被通知或者时间超q了(jin)调用被System.Threading.WaitOrTimerCallback包装的方法?/p>
U程池和Z事g的编E模式得线E池Ҏ(gu)册的WaitHandles的监控和对合适的WaitOrTimerCallback代表Ҏ(gu)的调用十分简?当WaitHandle被释放时)。这些做法其实很单。这里有一个线E不断的观测在线E池队列{待操作的状态。一旦等待操作完?一个线E将被执行与其对应的d。因?q个Ҏ(gu)随着出发触发事g的发生而增加一个线E?br />
让我们看看怎么随事件添加一个线E到U程?其实很简单。我们只需要创Z个ManualResetEventcȝ事g和一个WaitOrTimerCallback的代?然后我们需要一个携带代表状态的对象,同时我们也要军_休息间隔和执行方式。我们将上面的都d到线E池,q且Ȁ发一个事?
public void afunction(object o)
{
// do what ever the function is supposed to do.
}
//object that will carry the status information
public class anObject
{
}
//thread entry code
{
//create an event object
ManualResetEvent aevent = new ManualResetEvent (false);
// create an instance of WaitOrTimerCallback
WaitOrTimerCallback thread_method = new WaitOrTimerCallback (afunction);
// create an instance of anObject
anObject myobj = new anObject();
// decide how thread will perform
int timeout_interval = 100; // timeout in milli-seconds.
bool onetime_exec = true;
//add all this to the thread pool.
ThreadPool. RegisterWaitForSingleObject (aevent, thread_method, myobj, timeout_interval, onetime_exec);
// raise the event
aevent.Set();
}
在QueueUserWorkItem和RegisterWaitForSingleObjectҎ(gu)?U程池创Z(jin)一个后台的U程来回调。当U程池开始执行一个Q?两个Ҏ(gu)都将调用者的堆栈合ƈ到线E池的线E堆栈中。如果需要安全检查将耗费更多的时间和增加pȝ的负?因此可以通过使用它们对应的不安全的方法来避免安全(g)查。就是ThreadPool.UnsafeRegisterWaitForSingleObject 和ThreadPool.UnsafeQueueUserWorkItem?br />
你也可以对与{待操作无关的Q务排队?Timer-queue timers and registered wait operations也用线E池。它们的q回Ҏ(gu)也被攑օU程池排队?br />
U程池是非常有用?被广泛的用于。NETq_上的套节子编E?{待操作注册,q程计时器和异步的I/O。对于小而短的Q?U程池提供的机制也是十分便利处于多线E的。线E池对于完成许多独立的Q务而且不需要逐个的设|线E属性是十分便利的。但?你也应该很清?有很多的情况是可以用其他的方法来替代U程池的。比如说你的计划d或给每个U程特定的属?或者你需要将U程攑օ单个U程的空?而线E池是将所有的U程攑օ一个多U程I间),抑或是一个特定的d是很冗长?q些情况你最好考虑清楚,安全的办法比用线E池应该是你的选择?br />
System.Threading.Timer Class
Timercd于周期性的在分ȝU程执行d是非常有效的,它不能被l承?br />
q个cd其用来开发控制台应用E序,因ؓ(f)System.Windows.Forms.Time是不可用的。比如同来备份文件和(g)查数据库的一致性?/p>
当创建Timer对象?你药估计在第一个代理调用之前等待的旉和后来的每次成功调用之间的时间。一个定时调用发生在Ҏ(gu)的应得时间过?q且在后来周期性的调用q个Ҏ(gu)。你可以适应Timer的ChangeҎ(gu)来改变这些设|的值或者Timer失效。当定时器Timer不再使用?你应该调用DisposeҎ(gu)来释攑օ资源?br />
TimerCallback代表负责指定与Timer对象相关联的Ҏ(gu)(是要周期执行的d)和状态。它在方法应得的旉q去之后调用一ơƈ且周期性的调用q个Ҏ(gu)直到调用?jin)DisposeҎ(gu)释放?jin)Timer的所有资源。系l自动分配分ȝU程?br />
让我们来看一D代码看看事如何创徏Timer对象和用它的。我们首先要创徏一个TimerCallback代理,在后面的Ҏ(gu)中要使用到的。如果需?下一步我们要创徏一个状态对?它拥有与被代理调用的Ҏ(gu)相关联的特定信息。ؓ(f)?jin)ɘq些单一?我们传递一个空参数。我们将实例化一个Timer对象,然后再用ChangeҎ(gu)改变Timer的设|?最后调用DisposeҎ(gu)释放资源?br />
// class that will be called by the Timer
public class WorkonTimerReq
{
public void aTimerCallMethod()
{
// does some work
}
}
//timer creation block
{
//instantiating the class that gets called by the Timer.
WorkonTimerReq anObj = new WorkonTimerReq () ;
// callback delegate
TimerCallback tcallback = new TimerCallback(anObj. aTimerCallMethod) ;
// define the dueTime and period
long dTime = 20 ; // wait before the first tick (in ms)
long pTime = 150 ; // timer during subsequent invocations (in ms)
// instantiate the Timer object
Timer atimer = new Timer(tcallback, null, dTime, pTime) ;
// do some thing with the timer object
...
//change the dueTime and period of the Timer
dTime=100;
pTime=300;
atimer.Change(dTime, pTime) ;
// do some thing
...
atimer.Dispose() ;
...
}
异步~程
q部分内容如果要讲清楚本来就是很大的一部分,在这?我不打算详细讨论q个东西,我们只是需要直到它是什?因ؓ(f)多线E编E如果忽律异步的多线E编E显然是不应该的。异步的多线E编E是你的E序可能?x)用到的另外一U多U程~程Ҏ(gu)?br />
在前面的文章我们׃(jin)很大的篇q来介绍U程的同步和怎么实现U程的同?但是它有一个固有的致命的缺?你或许注意到?jin)这一炏V那是每个U程必须作同步调?也就是等到其他的功能完成,否则阻塞。当?某些情况?对于那些逻辑上相互依赖的d来说是够的。异步编E允许更加复杂的灉|性。一个线E可以作异步调用,不需要等待其他的东西。你可以使用q些U程作Q何的d,U程负责获取l果推进q行。这l予?jin)那些需要管理数目巨大的h而且负担不vh{待代h(hun)的企业的系l更好的可~性?br />
.NETq_提供?jin)一致的异步~程机制用于ASP.NET,I/O,Web Services,Networking,Message{?br />
后记
׃学习(fn)的时候很难找C文这斚w的资料,因此我就只好学习(fn)英文的资料,׃水^不高Q翻译的时候可能难免曲解原文的意思,希望大家能够指出Q同时希望这些东西能够给大家在学?fn)这斚w知识l予一定的参考和帮助Q那怕是一点点Q就很欣C(jin)?/p>
如果对处于阻塞状态的U程调用Thread.InterruptQ)(j)Ҏ(gu)ɾU程状态改变,但是?x)抛出ThreadInterupptedException异常Q你可以捕获q个异常q且做出处理Q也可以忽略q个异常而让q行时终止线E。在一定的{待旉之内QThread.InterruptQ)(j)和Thread.AbortQ)(j)都可以立卛_醒一个线E?br />
下面我们说明如何从一个线E中止另外一个线E。在q种情况下,我们可以通过使用Thread.AbortQ)(j)Ҏ(gu)来永久销毁一个线E,而且抛出ThreadAbortException异常。ɾl结的线E可以捕获到异常但是很难控制恢复Q仅有的办法是调用Thread.ResetAbortQ)(j)来取消刚才的调用Q而且只有当这个异常是׃被调用线E引L(fng)异常。因此,AU程可以正确的用Thread.AbortQ)(j)Ҏ(gu)作用于BU程Q但是BU程却不能调用Thread.ResetAbortQ)(j)来取消Thread.AbortQ)(j)操作?/p>
Thread.AbortQ)(j)Ҏ(gu)使得pȝ(zhn)?zhn)的销毁了(jin)U程而且不通知用户。一旦实施Thread.AbortQ)(j)操作Q该U程不能被重新启动。调用了(jin)q个Ҏ(gu)q不是意味着U程立即销毁,因此Z(jin)定U程是否被销毁,我们可以调用Thread.JoinQ)(j)来确定其销毁,Thread.JoinQ)(j)是一个阻塞调用,直到U程的确是终止了(jin)才返回。但是有可能一个线E调用Thread.InterruptQ)(j)Ҏ(gu)来中止另外一个线E,而这个线E正在等待Thread.JoinQ)(j)调用的返回?/p>
可能的不要用Suspend()Ҏ(gu)来挂起阻塞线E,因ؓ(f)q样很容易造成死锁。假设你挂v?jin)一个线E,而这个线E的资源是其他线E所需要的Q会(x)发生什么后果。因此,我们可能的l重要性不同的U程以不同的优先U,用Thread.PriorityQ)(j)Ҏ(gu)来代替用Thread.SuspendQ)(j)Ҏ(gu)?br />
ThreadcL很多的属性,q些重要的属性是我们多线E编E必d掌握的?br />
Thread.IsAlive属性:(x)获取一个|该值指C当前线E的执行状态。如果此U程已启动ƈ且尚未正常终止或中止Q则?trueQ否则ؓ(f) false?br />
Thread.Name 属性:(x)获取或设|线E的名称?br />
Thread.Priority 属性:(x)获取或设|一个|该值指C线E的调度优先U?br /> Thread.ThreadState 属性:(x)获取一个|该值包含当前线E的状态?br /> 在下面的例子中,我们看看怎么讄q些属性,在随后的例子中我们将详细的讨些属性?br /> 创徏一个线E,首先得实例化一个Threadc,在类得构造函C调用ThreadStart委派。这个委z含了(jin)U程从哪里开始执行。当U程启动后,Start()Ҏ(gu)启动一个新的线E。下面是例子E序?br />
using System;
using System.Threading ;
namespace LearnThreads
{
class Thread_App
{
public static void First_Thread()
{
Console.WriteLine("First thread created");
Thread current_thread = Thread.CurrentThread;
string thread_details = "Thread Name: " + current_thread.Name + "\r\nThread State: " + current_thread.ThreadState.ToString()+"\r\n Thread Priority level:"+current_thread.Priority.ToString();
Console.WriteLine("The details of the thread are :"+ thread_details);
Console.WriteLine ("first thread terminated");
}
public static void Main()
{
ThreadStart thr_start_func = new ThreadStart (First_Thread);
Console.WriteLine ("Creating the first thread ");
Thread fThread = new Thread (thr_start_func);
fThread.Name = "first_thread";
fThread.Start (); //starting the thread
}
}
}
在这个例子中Q创Z(jin)一个fThread的线E对象,q个U程负责执行First_Thread()Ҏ(gu)里面的Q务。当Thread的Start() Ҏ(gu)被调用时包含First_Thread()的地址ThreadStart的代理将被执行?br />
Thread状?/strong>
System.Threading.Thread.ThreadState属性定义了(jin)执行时线E的状态。线E从创徏到线E终止,它一定处于其中某一个状态。当U程被创建时Q它处在Unstarted状态,ThreadcȝStart() Ҏ(gu)ɾU程状态变为Running状态,U程一直处于这L(fng)状态,除非我们调用?jin)相应的?gu)使其挂v、阻塞、销毁或者自然终止。如果线E被挂vQ它?yu)处于Suspended状态,除非我们调用resumeQ)(j)Ҏ(gu)使其重新执行Q这时候线E将重新变ؓ(f)Running状态。一旦线E被销毁或者终止,U程处于Stopped状态。处于这个状态的U程不复存在,正如U程开始启动,U程不可能回到Unstarted状态。线E还有一个Background状态,它表明线E运行在前台q是后台。在一个确定的旉Q线E可能处于多个状态。据例子来说Q一个线E被调用?jin)Sleep而处于阻塞,而接着另外一个线E调用AbortҎ(gu)于这个阻塞的U程Q这时候线E将同时处于WaitSleepJoin和AbortRequested状态。一旦线E响应{为Sled或者中止,当销毁时?x)抛出ThreadAbortException异常?br />
U程优先U?/strong>
System.Threading.Thread.Priority枚D?jin)线E的优先U别Q从而决定了(jin)U程能够得到多少CPU旉。高优先U的U程通常?x)比一般优先的线E得到更多的CPU旉Q如果不止一个高优先U的U程Q操作系l将在这些线E之间@环分配CPU旉。低优先U的U程得到的CPU旉相对较少Q当q里没有高优先的线E,操作pȝ挑选下一个低优先U?的线E执行。一旦低优先U的U程在执行时遇到?jin)高优先U的U程Q它?yu)让出CPUl高优先U的U程。新创徏的线E优先Z般优先Q我们可以设|线E的优先U别的|如下面所C:(x)
Highest
AboveNormal
Normal
BelowNormal
Lowest
l论Q在q一部分Q我们讨Z(jin)U程的创ZU程的优先。System.Threading命名I间q包含了(jin)U程锁定、线E同步何通讯、多U程理cM?qing)死锁解决等{高U特性,在后面的部分我们l讨些内宏V?/p>
;
q回 "Brainiac"。有兛_ CPU 计算机名的解释,请参见图 1 对话框中的文本。?br />知道正确的计机名后Q将其传递给 RemotePiCalculator.GetPiCalculatorQ这h可以通过 PiCalculator 变量讉K该计机上的服务器对象。?br />如果用户单击?jin) CancelQ取消)(j)按钮Q将讄 Abort 属性。如果 Abort 属性ؓ(f) trueQ线E将停止计算。?br />对 MF.Invoke 的调用ɾU程可以安全地更斊WListView 中的l计数据Q参见图 2Q,即该 ListView 是由另一个线E创建的。在 32 位 Windows ~程中,l不允许在创建某个控件的U程之外处理该控件。?br />完成循环Q即计算完指定的所有 p 位数或者用户单击 Cancel [取消] 按钮Q后Q将调用U程的 AutoResetEvent 的 Set 函数。?br />当每个线E都调用其 AutoResetEvent 的 Set 函数后,返回对 WaitHandle.WaitAll 的调用ƈ昄l果。?br />U程同步
;
http://www.microsoft.com/china/msdn/library/dnbda/html/bdadotnetarch16.asp) 一文很有用Q它对?NET Web Service 和?NET Remoting q行?jin)比较。?br />Fabrice Bellard's Pi Page (
http://fabrice.bellard.free.fr/pi/) 提供?jin)一些用于计 p 值的有用公式和源代码Q包括 Digits of Pi E序中用的法的 C 语言源代码。?br />有关q程讉KE序的源代码Q请讉K www.personalmicrocosms.com/html/ra.html。此E序使用 .NET Remoting 昄q程计算机的桌面Qƈ使用本地计算机的键盘和鼠标运行远E计机。?br />有关数学化方面的内容Q请参阅 Petr Beckmann 著的《History of Pi》(St. Martin's Press 1971 q出版)(j)Q这是一本相当不错的书,因ؓ(f) p 的历史就是数学历史的微观反映。Beckmann 的书늛?jin) p 的数学历史以?qing)政d双Ӏ?br />Ingo Rammer 的《Advanced .NET Remoting》(Apress 2002 q出版)(j)是有ꐠRemoting 的权威指南。此书看h更适合从头到尾的详l阅诅R我倒是希望此书能够适合我的“随便翻Z的阅读?fn)惯。?br />有关 Hardcore Visual Studio .NET 和 Pinnacle Publishing 的详l信息,误问它们的 Web 站点
http://www.pinpub.com/?/a>| public interface ISynchronizeInvoke { object Invoke(Delegate method,object[] args); IAsyncResult BeginInvoke(Delegate method,object[] args); object EndInvoke(IAsyncResult result); bool InvokeRequired {get;} } |
| Form form; /* obtain a reference to the form, then: */ ISynchronizeInvoke synchronizer; synchronizer = form; if(synchronizer.InvokeRequired) { MethodInvoker invoker = new MethodInvoker(form.Close); synchronizer.Invoke(invoker,null); } else form.Close(); |
列表A:
public class Calculator : ISynchronizeInvoke int threadID = Thread.CurrentThread.GetHashCode(); Calculator calc; AddDelegate addDelegate = new AddDelegate(calc.Add); object[] arr = new object[2]; int sum = 0; /* Possible output: |
或许你ƈ不想q行同步调用Q因为它被打包发送到另一个线E中M(jin)。你可以通过BeginInvoke()和EndInvoke()Ҏ(gu)来实现它。你可以依照通用?NET非同步编E模式(asynchronous programming modelQ来使用q些Ҏ(gu)Q用BeginInvoke()来发送调用,用EndInvoke()来实现等待或用于在完成时q行提示以及(qing)攉q回l果?br />
q值得一提的是ISynchronizeInvokeҎ(gu)q安全cd?cd不符?x)导致在执行时被抛出异常Q而不是编译错误。所以在使用ISynchronizeInvoke时要格外注意Q因为编辑器无法(g)查出执行错误?br />
实现ISynchronizeInvoke要求你用一个代理来在后期绑定(late bindingQ中动态地调用Ҏ(gu)。每一U代理类型均提供DynamicInvoke()Ҏ(gu)Q?public object DynamicInvoke(object[]
args);
理论上来_(d)你必d一个方法代理放C个需要提供对象运行的真实的线E中去,qInvoke() 和BeginInvoke()Ҏ(gu)中的代理中调用DynamicInvoke()Ҏ(gu)。ISynchronizeInvoke的实现是一个非同一般的~程技巧,本文附带的源文g中包含了(jin)一个名为Synchronizer的帮助类Qhelper classQ和一个测试程序,q个试E序是用来论证列表A中的CalculatorcL如何用SynchronizercL实现ISynchronizeInvoke的。Synchronizer是ISynchronizeInvoke的一个普通实玎ͼ你可以用它的派生类或者将其本w作Z个对象来使用QƈISynchronizeInvoke实现指派l它?
用来实现Synchronizer的一个重要元素是使用一个名为WorkerThread的嵌套类Qnested classQ。WorkerThread中有一个工作项目(work itemQ查询。WorkItemcM包含Ҏ(gu)代理和参数。Invoke()和BeginInvoke()用来一个工作项目实例加入到查询里。WorkerThread新徏一?NET workerU程Q它负责监测工作目的查询Q务。查询到目之后Qworker?x)读取它们,然后调用DynamicInvoke()Ҏ(gu)?/p>