[英]How to notify thread from other class in C#
我有以下代码
(preproc、calc 和 display 是不同的类)
Thread procThread = new Thread(() => preproc.Start());
procThread.Start();
Thread calcThread = new Thread(() => calc.Start());
calcThread.Start();
Thread displayThread = new Thread(() => display.Start());
displayThread.Start();
在preproc.Start()
的启动方法中,我有三种方法
lock (data)
{
PreprocessSmth(-10.0, 10.0);
}
//I want to notify next thread here that preprocess ended and now next thread can run
//TODO: data can be calculated now
SaveResultsToDatabase();
DoSomethingElseThatTakesTime();
在PreprocessSmth(-10.0, 10.0);
之后我想通知calcThread
现在可以开始了。
我正在使用lock
,但我不知道它是否能保证我想要的。
编辑:使用 TPL 我做了类似的事情。 这是好的做法,还是我搞砸了?
主要方法
Task preprocTask = preproc.StartAsync();
Task calcTask = calc.StartAsync();
Task displayTask = Task.Run(() => display.Start());
Task.WaitAll(preprocTask, calcTask, displayTask);
Preproc class StartAsync 方法内部
private Task StartAsync()
{
PreprocessSmth(-10.0, 10.0);
//TODO: data can be calculated now
Task save = SaveResultsToDatabaseAsync();
Task doSomething = DoSomethingElseThatTakesTimeAsync();
return Task.WhenAll(save, doSomething);
}
Calc class StartAsync 与 Preproc StartAsync 几乎相同。 所以流程是这样的: Main->preproc.StartAsync()->PreprocessSmth(), then asynchronously SavingToDb and DoSomething, ->calc.StartAsync()->CalcSmth() then SaveDataToDb asynchronously
等等...
操作:
如何在 C# 中通知来自其他 class 的线程......以及在 PreprocessSmth(-10.0, 10.0) 之后; 我想通知 calcThread 现在可以开始了。
因此,首先进行审查。 如果我们检查您的原始代码:
Thread procThread = new Thread(() => preproc.Start());
procThread.Start();
Thread calcThread = new Thread(() => calc.Start());
calcThread.Start();
Thread displayThread = new Thread(() => display.Start());
displayThread.Start();
...我们可以看到创建了三 (3) 个Thread
来驱动preproc
、 calc
和display
,它们都在运行的 state 中。 我了解您想通知calcThread
,它可能会在PreprocessSmth
完成后开始。
与老式Thread
编程相结合的一种简单方法是Windows 同步对象,这是大多数操作系统的共同特征。
MSDN 对这个主题有这样的说法(我的重点):
同步 object是一个 object 其句柄可以在一个等待函数中指定以协调多个线程的执行。 多个进程可以拥有同一个同步 object 的句柄,使进程间同步成为可能。 告诉我更多...
...和 NET(我的重点):
.NET 提供了一系列类型,可用于同步对共享资源的访问或协调线程交互...多个 .NET 同步原语派生自
System.Threading.WaitHandle
class 封装了本机操作系统处理和使用同步的信号线程交互机制。 告诉我更多...
...具体来说:
System.Threading.ManualResetEvent
,它派生自EventWaitHandle
,并且在发出信号时停留在发出信号的 state 中,直到调用Reset
方法。 告诉我更多...
想到ManualResetEvent
的最简单方法就像浴室水龙头。 它最初可以关闭,但如果打开水龙头,它将一直保持这种状态,直到您家中的某个人将其关闭……或者当当地市议会因未付账单而切断您的供水时。
考虑到这一点,让我们将ManualResetEvent
引入您的代码,如下所示:
class Program
{
#region Statics
static void Main(string[] args)
{
Logger.WriteLine($"Inside Main, thread ID is {Environment.CurrentManagedThreadId}");
// initial state is NOT set (i.e. the "bathroom tap" is off)
var goodToGoEvent = new ManualResetEvent(false); // <--- NEW
var preproc = new PreProc();
var procThread = new Thread(() => preproc.Start(goodToGoEvent)); // pass in event
procThread.Start();
var calc = new Calc();
var calcThread = new Thread(() => calc.Start(goodToGoEvent)); // pass in event
calcThread.Start();
var display = new Display();
var displayThread = new Thread(() => display.Start());
displayThread.Start();
// wait for Calc to finish
Logger.WriteLine("Main thread - waiting for Calc thread to complete...");
calcThread.Join();
Logger.WriteLine("Main thread - waiting for Calc thread to complete...OK");
Logger.WriteLine("Press any key to exit");
Console.ReadKey();
}
#endregion
}
internal class Display
{
#region Methods
public void Start()
{
// NOP
}
#endregion
}
internal class Calc
{
#region Methods
/// <summary>
/// Starts the specified good to go event.
/// </summary>
/// <param name="goodToGoEvent">The event to wait on that indicates "good-to-go".</param>
public void Start(ManualResetEvent goodToGoEvent)
{
Logger.WriteLine("Calc - waiting for good-to-go event to be signaled...");
goodToGoEvent.WaitOne(); // block current thread until event is signaled
Logger.WriteLine("Calc - waiting for good-to-go event to be signaled...OK");
// now that PreProc is complete do what needs to be done here
}
#endregion
}
internal class PreProc
{
#region Fields
private object data = new object();
#endregion
#region Methods
/// <summary>
/// Starts the specified good to go event.
/// </summary>
/// <param name="goodToGoEvent">the event to signal once processing is complete.</param>
public void Start(ManualResetEvent goodToGoEvent)
{
//lock (data) // <--- not necessary in this example unless other threads will modify data concurrently
{
PreprocessSmth(-10.0, 10.0);
}
//I want to notify next thread here that preprocess ended and now next thread can run
Logger.WriteLine("PreProc - setting goodToGoEvent to signaled");
goodToGoEvent.Set(); // let other threads know that preprocess has ended
//TODO: data can be calculated now
SaveResultsToDatabase();
DoSomethingElseThatTakesTime();
}
private void DoSomethingElseThatTakesTime()
{
// NOP
}
private void PreprocessSmth(double d, double d1)
{
Logger.WriteLine("PreProc - Preprocessing...(sleeping 5 secs)");
Thread.Sleep(TimeSpan.FromSeconds(5)); // simulate lengthy operation
Logger.WriteLine("PreProc - Preprocessing...OK");
}
private void SaveResultsToDatabase()
{
// NOP
}
#endregion
}
public static class Logger
{
#region Static fields
private static readonly object Locker = new object();
#endregion
#region Statics
public static void WriteLine(string message)
{
lock (Locker)
{
Console.WriteLine($"{DateTime.Now:hh:mm:ss.ff} [{Environment.CurrentManagedThreadId}] {message}");
}
}
#endregion
}
在我的代码中,我引入了一个ManualResetEvent
类型的新变量goodToGoEvent
,它被传递给preproc.Start
和calc.Start
。 preproc
的工作是Set
事件,而calc
Wait
它。 把它想象成一组交通信号灯。
下面是实际代码,方括号 ( [ ] ) 中显示的数字是对应的线程 ID:
根据您使用/仅限于哪个 .NET 版本,您可能需要查看 Microsoft 的任务并行库、 Task
以及它是如何用async/await
封装在功能区中的(在 .NET 4.5+ 中体验最佳)。
如果我可以这么大胆:
async/await 是进行异步编程的现代且最简单的方法,无论作业是否受 I/O 限制; 任务是否需要线程。 无偿自我推销
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.