好多天没有更新Blog了,一直都在忙着寻找如何将IronPython集成至GUI中的方法。一开始我把问题看得太简单了,因为我看了来自C
odeProject的ShellControl - A console emulation control这篇文章之后,很幼稚地认为只需要把源代码中的cmd.exe换IronPythonConsole.exe 就可以大功告成了,然而事实证明
我的想法是很愚蠢的。尽管IronPythonConsole与cmd同为可执行文件,但是它们与作为输入输出的RichTextBox之间的关系是不同的。对
cmd而言,是一种顺序的处理方式:TextBox接受用户输入-> 用户按下Enter触发相应的EventHandler,在EventHandler中创建Process
以运行cmd.exe -> 将结果返回至TextBox。在这个过程中,每一条指令的输入都会相应地创建新的Process,而这个Process的life
cycle仅仅存在于用户按下Enter触发的事件响应函数中;反观IronPythonConsole的情况就不是这样的了,我们需要的是一个GUI Thread
来响应用户的输入,同时需要一个Worker Thread调用IronPythonConsole来完成用户输入并给出相应的输出,很明显我需要进行多线程的
开发了。面对着多线程,我真的很困窘,因为自己在这个方面的经验几乎为零。不过没有办法,为了FantasyPython,只能明知山有虎,偏向
虎山行了。
也许是自己天性愚钝吧,看了两天的文章,也还没有很好的solution,不过对于Multithreading倒是有了一点小小的认识,谨记于 此。首先是使用多线程的重要性了。这点其实不必多言,大家都会知道把占用大量CPU周期的数据处理放到GUI Thread中,造成GUI无法响应 用户的操作是一种十分糟糕的做法。为了实现更好的用户体验,就应该创建新的进程来处理持续时间较长的操作,通常我们会把负责非UI操作 的进程称为Worker Thread(工作进程)。重要性说完了,让我们关注到更具体的多线程实现上来。
在.NET中进行多线程开发,会有很多选择,其中最常见的就是使用Control.Invoke方法了。Invoke方法提供了一种在Worker Thread 调用GUI Thread中delegate的途径。同时结合Control.InvokeRequired的属性,我们也可以轻易地判断某个线程是否为创建该Control的线 程。为了对Invoke方法有更深入的认识,我仔细地阅读了CodeProject上《Worker Threads In C#》一文[1]。在文中有这样的代码:
m_form.Invoke(m_form.m_DelegateAddString, new Object[]
{s}
);
这里给出了Invoke方法的一种使用方式,但是可惜的是,我并不能对其使用的必要性有充分的理解。因为我把这段代码改为 m_form.AddString(s),并且将AddString方法的access modifier由private改为public,程序仍然是运行好好的。那么Invoke方法的 意义在于什么呢?而MSDN给Invoke方法下的定义又是如此的简单:Executes the specified delegate on the thread that owns the control's underlying window handle. 真的是看不明白了,烦请各位朋友不吝赐教。
问题虽然有,但是认识还得接着说。多线程开发很重要的一点就是线程间的通信问题,在CodeProject的这篇文章中,Worker Thread与 GUI Thread是通过ManualResetEvent来实现的。我们从文中的代码:
// Worker Thread
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
if ( m_EventStop.WaitOne(0, true) )
{
m_EventStopped.Set();
return;
}
![None.gif](/Images/OutliningIndicators/None.gif)
// GUI Thread
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
if ( m_WorkerThread != null && m_WorkerThread.IsAlive )
{
m_EventStopThread.Set();
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
while (m_WorkerThread.IsAlive)
{
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if ( WaitHandle.WaitAll((new ManualResetEvent[]
{m_EventThreadStopped}), 100,true) )
{
break;
}
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
Application.DoEvents();
}
}
可以看到Worker Thread与GUI Thread之间的通信过程:
1、当Worker Thread处于活动状态,而GUI Thread通过设置m_EventStopThread的状态向Worker Thread发出Signal,并使自己进 入循环等待状态,直至接收到由Worker Thread发出的Signal;
2、Worker Thread在接收到该Signal之后采取相应的操作,例子中的操作就是通过设置m_EventStopped的状态向GUI Thread发出自己已 经停止的Signal并且返回;
3、GUI Thread接收到来自Worker Thread发出的Signal后,跳出循环;
呼,终于说完了。由于自己刚刚开始接触C#的MultiThreading开发,疏漏一定不少。请各位路过的朋友不要错过扔砖头的机会哦,^_^
[1] 小新0574为这篇不错的文章提供了译文,有兴趣的朋友可以参考一下中文版。
也许是自己天性愚钝吧,看了两天的文章,也还没有很好的solution,不过对于Multithreading倒是有了一点小小的认识,谨记于 此。首先是使用多线程的重要性了。这点其实不必多言,大家都会知道把占用大量CPU周期的数据处理放到GUI Thread中,造成GUI无法响应 用户的操作是一种十分糟糕的做法。为了实现更好的用户体验,就应该创建新的进程来处理持续时间较长的操作,通常我们会把负责非UI操作 的进程称为Worker Thread(工作进程)。重要性说完了,让我们关注到更具体的多线程实现上来。
在.NET中进行多线程开发,会有很多选择,其中最常见的就是使用Control.Invoke方法了。Invoke方法提供了一种在Worker Thread 调用GUI Thread中delegate的途径。同时结合Control.InvokeRequired的属性,我们也可以轻易地判断某个线程是否为创建该Control的线 程。为了对Invoke方法有更深入的认识,我仔细地阅读了CodeProject上《Worker Threads In C#》一文[1]。在文中有这样的代码:
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](/Images/dot.gif)
![None.gif](/Images/OutliningIndicators/None.gif)
这里给出了Invoke方法的一种使用方式,但是可惜的是,我并不能对其使用的必要性有充分的理解。因为我把这段代码改为 m_form.AddString(s),并且将AddString方法的access modifier由private改为public,程序仍然是运行好好的。那么Invoke方法的 意义在于什么呢?而MSDN给Invoke方法下的定义又是如此的简单:Executes the specified delegate on the thread that owns the control's underlying window handle. 真的是看不明白了,烦请各位朋友不吝赐教。
问题虽然有,但是认识还得接着说。多线程开发很重要的一点就是线程间的通信问题,在CodeProject的这篇文章中,Worker Thread与 GUI Thread是通过ManualResetEvent来实现的。我们从文中的代码:
![None.gif](/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](/Images/dot.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedBlockEnd.gif](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![None.gif](/Images/OutliningIndicators/None.gif)
![None.gif](/Images/OutliningIndicators/None.gif)
![ExpandedBlockStart.gif](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](/Images/OutliningIndicators/ContractedBlock.gif)
![dot.gif](/Images/dot.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](/Images/OutliningIndicators/ContractedSubBlock.gif)
![dot.gif](/Images/dot.gif)
![ExpandedSubBlockStart.gif](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](/Images/OutliningIndicators/ContractedSubBlock.gif)
![dot.gif](/Images/dot.gif)
![dot.gif](/Images/dot.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockEnd.gif](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![InBlock.gif](/Images/OutliningIndicators/InBlock.gif)
![ExpandedSubBlockEnd.gif](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![ExpandedBlockEnd.gif](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![None.gif](/Images/OutliningIndicators/None.gif)
可以看到Worker Thread与GUI Thread之间的通信过程:
1、当Worker Thread处于活动状态,而GUI Thread通过设置m_EventStopThread的状态向Worker Thread发出Signal,并使自己进 入循环等待状态,直至接收到由Worker Thread发出的Signal;
2、Worker Thread在接收到该Signal之后采取相应的操作,例子中的操作就是通过设置m_EventStopped的状态向GUI Thread发出自己已 经停止的Signal并且返回;
3、GUI Thread接收到来自Worker Thread发出的Signal后,跳出循环;
呼,终于说完了。由于自己刚刚开始接触C#的MultiThreading开发,疏漏一定不少。请各位路过的朋友不要错过扔砖头的机会哦,^_^
[1] 小新0574为这篇不错的文章提供了译文,有兴趣的朋友可以参考一下中文版。