C#多线程设计示例

C#多线程设计示例,c#,multithreading,design-patterns,C#,Multithreading,Design Patterns,我对C#/.Net比较陌生。我正在开发一个需要多线程的桌面应用程序。我提出了以下模式作为基础。我想知道是否有人能指出如何在编码、线程安全和高效方面做得更好 希望这有点道理 公共抽象类ThreadManagerBase { //静态类变量 私有静态ThreadManagerBase实例=null; 私有静态BackgroundWorker线程=null; 私有静态ProgressBarUIForm progress=null; /// ///创建该类的新实例。内部内容由派生类来确定。 ///任

我对C#/.Net比较陌生。我正在开发一个需要多线程的桌面应用程序。我提出了以下模式作为基础。我想知道是否有人能指出如何在编码、线程安全和高效方面做得更好

希望这有点道理


公共抽象类ThreadManagerBase
{
//静态类变量
私有静态ThreadManagerBase实例=null;
私有静态BackgroundWorker线程=null;
私有静态ProgressBarUIForm progress=null;
/// 
///创建该类的新实例。内部内容由派生类来确定。
///任何时候都只能运行一个实例。应该只有主线程和此线程。
/// 
公共抽象静态ThreadManagerBase NewInstance();
/// 
///清除实例。
/// 
公共静态void ClearInstance()
{
实例=null;
}
/// 
///使用一些预设值初始化后台工作程序。
///显示进度条。
/// 
私有抽象静态void InitializeThread()
{
线程=新的BackgroundWorker();
thread.WorkerReportsProgress=true;
thread.workersupport扫描单元=true;
thread.DoWork+=新的DoWorkEventHandler(thread_DoWork);
thread.RunWorkerCompleted+=新的RunWorkerCompletedEventHandler(线程\u RunWorkerCompleted);
thread.ProgressChanged+=新的ProgressChangedEventHandler(thread\u ProgressChanged);
thread.RunWorkerAsync();
进度=新的ProgressBarUIForm();
progress.EnableCancelButton=true;
progress.usercancelled+=新事件handlercanceclicked(progress\u usercancelled);
progress.ShowDialog();
thread.Dispose();
线程=null;
}
私有静态无效进度\u usercancelled(bool usercancelled)
{
CancelAsync();
}
私有静态无效线程\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
progress.SetProgressLevel=e.ProgressPercentage;
progress.SetProgressMessage=e.UserState.ToString();
}
私有静态无效线程\u RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
progress.Close();
进度=空;
}
私有静态无效线程\u DoWork(对象发送方,DoWorkEventArgs e)
{
加工();
}
私有抽象静态void ProcessWork()
{
//在这里做所有的事情。
//派生类将负责管道。
}
}

除非你想被调羹,否则你不需要BackgroundWorker,只要你遵守规则,普通线程是完全可以接受的。

除非你想被调羹,否则你不需要BackgroundWorker,普通线程是完全可以接受的,只要你遵守规则。

我看不出有什么好的理由在BackgroundWorker之上创建这种抽象。
如果您坚持的话,那只是一个警告:我不确定它在以后的版本中是否发生了更改,但在Net2.0中,不可能真正取消DoWork处理程序(除非它在被要求停止时偶尔检查一次)。阅读以获得解决方案

我看不出有什么好的理由在BackgroundWorker之上创建这种抽象。 如果您坚持的话,那只是一个警告:我不确定它在以后的版本中是否发生了更改,但在Net2.0中,不可能真正取消DoWork处理程序(除非它在被要求停止时偶尔检查一次)。阅读以获得解决方案

你有没有调查过这个问题?这是一个非常好的库,它需要大量的线程工作

在MSDN上也有很多关于线程模式的文章,您也应该对此进行研究。线程可以很快变得非常复杂。很高兴有其他人来思考所有可能出错的重要内容,并将其简化为库或模式。当然,如果您不了解任何特定解决方案的局限性,这也有危险。所以,无论你选择什么解决方案,都要确保你研究得很好。

你有没有研究过这个问题?这是一个非常好的库,它需要大量的线程工作


在MSDN上也有很多关于线程模式的文章,您也应该对此进行研究。线程可以很快变得非常复杂。很高兴有其他人来思考所有可能出错的重要内容,并将其简化为库或模式。当然,如果您不了解任何特定解决方案的局限性,这也有危险。所以,无论你选择什么解决方案,一定要好好研究。

我也做过类似的事情。如果您确实有多个要执行的任务,但不希望在整个项目中复制BackgroundWorker代码,那么这是一个很好的理由。我没有将progressbar绑定到实际的基类,我只是在主窗体中使用它。以下是我提出的解决方案:

以下是基类:


   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
   }

我做过类似的事情。如果您确实有多个要执行的任务,但不希望在整个项目中复制BackgroundWorker代码,那么这是一个很好的理由。我没有将progressbar绑定到实际的基类,我只是在主窗体中使用它。以下是我提出的解决方案:

以下是基类:


   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
   }

以下是我发布的示例的示例测试类:


   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
         }
      }
   }
下面是主窗体的外观(非常基本的示例):


以下是我发布的示例的示例测试类:


   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
         }
      }
   }
下面是主窗体的外观(非常基本的示例):


我目前正在调查Threadmare的一个C#项目。它看起来非常非常有用。它是用Delphi编写的,但原则适用于任何能够处理事件的语言。

我目前正在为一个C#项目调查Threadmare。它是罗