2009-02-27 6 views
2

C#/ Netには比較的新しいです。マルチスレッドが必要なデスクトップアプリケーションを開発しています。下のパターンをベースに思いつきました。私は、誰かがコーディング、スレッドセーフで効率的であるという点でそれをより良くする方法を指摘できるかどうか疑問に思っていました。C#マルチスレッド設計の例

うまくいけば、これは意味をなさないでしょう。


public abstract class ThreadManagerBase 
{ 
    // static class variables 

    private static ThreadManagerBase instance = null; 
    private static BackgroundWorker thread = null; 
    private static ProgressBarUIForm progress = null; 

    /// <summary> 
    /// Create a new instance of this class. The internals are left to the derived class to figure out. 
    /// Only one instance of this can run at any time. There should only be the main thread and this thread. 
    /// </summary> 
    public abstract static ThreadManagerBase NewInstance(); 

    /// <summary> 
    /// Clears the instance. 
    /// </summary> 
    public static void ClearInstance() 
    { 
     instance = null; 
    } 

    /// <summary> 
    /// Initializes the background worker with some presets. 
    /// Displays progress bar. 
    /// </summary> 
    private abstract static void InitializeThread() 
    { 
     thread = new BackgroundWorker(); 

     thread.WorkerReportsProgress = true; 
     thread.WorkerSupportsCancellation = true; 

     thread.DoWork += new DoWorkEventHandler(thread_DoWork); 
     thread.RunWorkerCompleted += new RunWorkerCompletedEventHandler(thread_RunWorkerCompleted); 
     thread.ProgressChanged += new ProgressChangedEventHandler(thread_ProgressChanged); 

     thread.RunWorkerAsync(); 

     progress = new ProgressBarUIForm(); 

     progress.EnableCancelButton = true; 

     progress.UserCanceled += new EventHandlerCancelClicked(progress_UserCanceled); 

     progress.ShowDialog(); 

     thread.Dispose(); 

     thread = null; 
    } 

    private static void progress_UserCanceled(bool userCanceled) 
    { 
     thread.CancelAsync(); 
    } 

    private static void thread_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     progress.SetProgressLevel = e.ProgressPercentage; 
     progress.SetProgressMessage = e.UserState.ToString(); 
    } 

    private static void thread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     progress.Close(); 

     progress = null; 
    } 

    private static void thread_DoWork(object sender, DoWorkEventArgs e) 
    { 
     ProcessWork(); 
    } 

    private abstract static void ProcessWork() 
    { 
     // do actuall stuff here. 
     // the derived classes will take care of the plumbing. 
    } 
} 
+0

デザインパターンは特定の言語で表現されていないため、これはデザインパターンではありません。 – Brian

+0

Duleyが注目し、変更しました。 – Brownman98

答えて

-2

あなたがspoonfedされる場合を除き、あなたは、通常のスレッドは限り、あなたはルールに従うように、完全に許容され、BackgroundWorkerのを必要としません。

+2

あなたはあまりにも "ルール"を参照していますか? – Brownman98

+1

私はあなたがスレッドのMicrosoftのガイドに従うことができると思います。 http://msdn.microsoft.com/en-us/library/e1dx6b2h.aspx正しいはずです;) –

+1

スプーンフィードで何が問題になっていますか? –

0

BackgroundWorkerよりもこの抽象化を作成するのは正当な理由がありません。 あなたが主張するならば、ちょうど警告:私はそれが後のリリースで変更されたかどうかはわかりませんが、NET 2.0ではDoWorkハンドラを本当にキャンセルすることはできませんでした。やめる)。ソリューションについてはhereをお読みください。

1

Microsoft Parallel Extensions to .NET Framework 3.5を調べましたか?これは、スレッディングから多くの作業を取り除くかなり良いライブラリです。

MSDNには、調査する必要があるスレッドパターンについての記事もたくさんあります。スレッディングは本当に非常に複雑になります。間違っている可能性のある重要なものを誰かに持ってもらい、ライブラリやパターンに単純化するのはいいことです。もちろん、特定のソリューションの問題点を理解していなければ、それにも危険が伴います。だから、どんなソリューションを選んでもよく研究してください。

0

私はこれに類似したことをしました。あなたが実行したい複数のタスクを持っているのに、プロジェクト全体を通してBackgroundWorkerコードを複製したいのであれば、良い理由があります。私はプログレスバーを実際の基本クラスに結びつけてはいけません。私はちょうどメインフォームにそれを持っています。ここで私が思いついた解決されています

次は、基本クラスである:

 

    public abstract class Operation 
    { 
     #region public Event Handlers 

     /// 
     /// The event that updates the progress of the operation 
     /// 
     public event OperationProgressChangedEventHandler OperationProgressChanged; 

     /// 
     /// The event that notifies that the operation is complete (and results) 
     /// 
     public event OperationCompletedEventHandler OperationCompleted; 

     #endregion 

     #region Members 

     // Whether or not we can cancel the operation 
     private bool mWorkerSupportsCancellation = false; 
     // The task worker that handles running the operation 
     private BackgroundWorker mOperationWorker; 
     // The operation parameters 
     private object[] mOperationParameters; 

     #endregion 

     /// 
     /// Base class for all operations 
     /// 
     public Operation(params object[] workerParameters) 
     { 
     mOperationParameters = workerParameters; 
     // Setup the worker 
     SetupOperationWorker(); 
     } 

     #region Setup Functions 

     /// 
     /// Setup the background worker to run our Operations 
     /// 
     private void SetupOperationWorker() 
     { 
     mOperationWorker = new BackgroundWorker(); 
     mOperationWorker.WorkerSupportsCancellation = mWorkerSupportsCancellation; 
     mOperationWorker.WorkerReportsProgress = true; 
     mOperationWorker.WorkerSupportsCancellation = true; 
     mOperationWorker.DoWork += new DoWorkEventHandler(OperationWorkerDoWork); 
     mOperationWorker.ProgressChanged += new ProgressChangedEventHandler(OperationWorkerProgressChanged); 
     mOperationWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OperationWorkerRunWorkerCompleted); 
     } 

     #endregion 

     #region Properties 

     /// 
     /// Whether or not to allow the user to cancel the operation 
     /// 
     public bool CanCancel 
     { 
     set 
     { 
      mWorkerSupportsCancellation = value; 
     } 
     } 

     #endregion 

     #region Operation Start/Stop Details 

     /// 
     /// Start the operation with the given parameters 
     /// 
     /// The parameters for the worker 
     public void StartOperation() 
     { 
     // Run the worker 
     mOperationWorker.RunWorkerAsync(mOperationParameters); 
     } 

     /// 
     /// Stop the operation 
     /// 
     public void StopOperation() 
     { 
     // Signal the cancel first, then call cancel to stop the test 
     if (IsRunning()) 
     { 
      // Sets the backgroundworker CancelPending to true, so we can break 
      // in the sub classes operation 
      mOperationWorker.CancelAsync(); 
      // This allows us to trigger an event or "Set" if WaitOne'ing 
      Cancel(); 
      // Wait for it to actually stop before returning 
      while (IsRunning()) 
      { 
       Application.DoEvents(); 
      } 
     } 
     } 

     /// 
     /// Whether or not the operation is currently running 
     /// 
     /// 
     public bool IsRunning() 
     { 
     return mOperationWorker.IsBusy; 
     } 

     #endregion 

     #region BackgroundWorker Events 

     /// 
     /// Fires when the operation has completed 
     /// 
     /// 
     /// 
     private void OperationWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
     // Allow the sub class to clean up anything that might need to be updated 
     Clean(); 

     // Notify whoever is register that the operation is complete 
     if (OperationCompleted != null) 
     { 
      OperationCompleted(e); 
     } 
     } 

     /// 
     /// Fires when the progress needs to be updated for a given test (we might not care) 
     /// 
     /// 
     /// 
     private void OperationWorkerProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
     // Notify whoever is register of what the current percentage is 
     if (OperationProgressChanged != null) 
     { 
      OperationProgressChanged(e); 
     } 
     } 

     /// 
     /// Fires when we start the operation (this does the work) 
     /// 
     /// 
     /// 
     private void OperationWorkerDoWork(object sender, DoWorkEventArgs e) 
     { 
     // Run the operation 
     Run(sender, e); 
     } 

     #endregion 

     #region Abstract methods 

     /// 
     /// Abstract, implemented in the sub class to do the work 
     /// 
     /// 
     /// 
     protected abstract void Run(object sender, DoWorkEventArgs e); 

     /// 
     /// Called at the end of the test to clean up anything (ex: Disconnected events, etc) 
     /// 
     protected abstract void Clean(); 

     /// 
     /// If we are waiting on something in the operation, this will allow us to 
     /// stop waiting (ex: WaitOne). 
     /// 
     protected abstract void Cancel(); 

     #endregion 
    } 
 
0

次は私が掲示例えばサンプルテストクラスです:

 

    class TestOperation : Operation 
    { 
     AutoResetEvent mMsgRec; 

     public TestOperation(params object[] workerParameters) 
     : base(workerParameters) 
     { 
     CanCancel = true; 
     mMsgRec = new AutoResetEvent(false); 
     //mSomeEvent += DoSomething(); 
     } 

     protected override void Cancel() 
     { 
     mMsgRec.Set(); 
     } 

     protected override void Clean() 
     { 
     //mSomeEvent -= DoSomething(); 
     } 

     protected override void Run(object sender, DoWorkEventArgs e) 
     { 
     BackgroundWorker bg = (BackgroundWorker)sender; 
     for (int i = 0; !bg.CancellationPending && (i < 90); i++) 
     { 
      bg.ReportProgress(i); 
      Thread.Sleep(100); 
     } 

     for (int i = 90; !bg.CancellationPending && (i < 100); i++) 
     { 
      mMsgRec.WaitOne(2000, false); 
      bg.ReportProgress(i); 
     } 

     if (bg.CancellationPending) 
     { 
      e.Cancel = true; 
     } 
     else 
     { 
      e.Result = "Complete"; // Or desired result 
     } 
     } 
    } 
 

そしてここにはありますメインフォームの外観(非常に基本的な例):

 

    public partial class Form1 : Form 
    { 
     TestOperation t; 

     public Form1() 
     { 
     InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
     t = new TestOperation(); 
     t.CanCancel = true; 

     t.OperationProgressChanged += new OperationProgressChangedEventHandler(t_OperationProgressChanged); 
     t.OperationCompleted += new OperationCompletedEventHandler(t_OperationCompleted); 

     t.StartOperation(); 
     } 

     void t_OperationCompleted(RunWorkerCompletedEventArgs e) 
     { 
     progressBar1.Value = 0; 
     } 

     void t_OperationProgressChanged(ProgressChangedEventArgs e) 
     { 
     progressBar1.Value = e.ProgressPercentage; 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
     t.StopOperation(); 
     } 
    } 
 
関連する問題