// 通過創建委托解決傳遞參數問題
private void _btnRun_Click( object sender, System.EventArgs e )
{
RunTaskDelegate runTask = new RunTaskDelegate( RunTask );
// 委托同步調用方式
runTask( Convert.ToInt16( _txtSecond.Value ) );
}
//通過創建委托解決傳遞參數問題,通過委托的異步調用消除用戶界面線程的阻塞問題
private void _btnRun_Click( object sender, System.EventArgs e )
{
RunTaskDelegate runTask = new RunTaskDelegate( RunTask );
// 委托異步調用方式
runTask.BeginInvoke( Convert.ToInt16( _txtSecond.Value ), null, null );
}
多線程安全
到這里為止,我們已經解決了長任務的難題和傳遞參數的困擾。但是我們真的解決了全部問題嗎?回答是否定的。
我們知道 Windows 編程中有一個必須遵守的原則,那就是在一個窗體創建線程之外的任何線程中都不允許操作窗體。
我們上面的程序就是存在這樣的問題:工作線程是在 ShowProgress 方法中修改了用戶界面的進度條的屬性。那為什么程序運行沒有出現問題,運行正常呢?
沒有發生問題是因為是現在的Windows XP操作系統對這類問題有非常健壯的解決方法,讓我們避免了問題的發生。但是我們現在的程序不能保證在其他的操作系統能夠運行正常!
真正的解決方法是我們能夠認識到問題所在,並在程序中加以避免。

如何避免多線程的窗體資源訪問的安全問題呢?其實非常簡單,有兩種方法:
一種方法就是不管線程是否是用戶界面線程,對用戶界面資源的訪問統一由委托完成;
另一種方法是在每個 Windows Forms 用戶界面類中都有一個 InvokeRequired 屬性,它用來標識當前線程是否能夠直接訪問窗體資源。我們只需要檢查這個屬性的值,只有當允許直接訪問窗體資源時才直接訪問相應的資源,否則,就需要通過 委托進行訪問了。
采用第一種安全的方法的代碼片斷如下:
// 顯示進度條的委托聲明
delegate void ShowProgressDelegate( int totalStep, int currentStep );
// 顯示進度條
void ShowProgress( int totalStep, int currentStep )
{
_Progress.Maximum = totalStep;
_Progress.Value = currentStep;
}
// 執行任務的委托聲明
delegate void RunTaskDelegate( int seconds );
// 執行任務
void RunTask( int seconds )
{
ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );
// 每 1 / 4 秒 顯示進度一次
for( int i = 0; i < seconds * 4; i++ )
{
Thread.Sleep( 250 );
// 顯示進度條
this.Invoke( showProgress, new object[] { seconds * 4, i + 1 } );
}
}
采用第二種安全的方法的代碼片斷如下:
// 顯示進度條的委托聲明
delegate void ShowProgressDelegate( int totalStep, int currentStep );
// 顯示進度條
void ShowProgress( int totalStep, int currentStep )
{
if( _Progress.InvokeRequired )
{
ShowProgressDelegate showProgress = new ShowProgressDelegate( ShowProgress );
// 為了避免工作線程被阻塞,采用異步調用委托
this.BeginInvoke( showProgress, new object[] { totalStep, currentStep } );
}
else
{
_Progress.Maximum = totalStep;
_Progress.Value = currentStep;
}
}
// 執行任務的委托聲明
delegate void RunTaskDelegate( int seconds );
// 執行任務
void RunTask( int seconds )
{
// 每 1 / 4 秒 顯示進度一次
for( int i = 0; i < seconds * 4; i++ )
{
Thread.Sleep( 250 );
// 顯示進度條
ShowProgress( seconds * 4, i + 1 );
}
}
至此,我們用了幾個示例說明了如何執行長任務、如何通過多線程異步處理任務進度的顯示並解決了多線程的安全性等問題。希望能夠給大家對理解多線程編程、委托的使用、異步調用等方面提供一些幫助,也希望能和大家進行進一步的溝通和交流。
