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