C# 访问共享资源时通过静态锁进行线程同步
我正在尝试修复两个线程的线程同步问题,这两个线程都访问一个资源。在本例中,该资源是C# 访问共享资源时通过静态锁进行线程同步,c#,multithreading,C#,Multithreading,我正在尝试修复两个线程的线程同步问题,这两个线程都访问一个资源。在本例中,该资源是引擎 在这里,两次启动正在启动引擎,一个线程正在停止它。目标是获得发动机启动的最终结果 澄清:我不控制ThreadOne/ThreadTwo中的代码,需要在生命周期类中进行同步 在本例中,实现这一点的最佳方法是什么 using System; using System.Threading; class Program { static void Main(string[] args) {
引擎
在这里,两次启动正在启动引擎,一个线程正在停止它。目标是获得发动机启动的最终结果
澄清:我不控制ThreadOne/ThreadTwo中的代码,需要在生命周期
类中进行同步
在本例中,实现这一点的最佳方法是什么
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
new Thread(ThreadOne).Start();
new Thread(ThreadTwo).Start();
Console.Read();
}
private static void ThreadOne(object obj)
{
Lifecycle.Start();
Thread.Sleep(500);
Lifecycle.Stop();
}
private static void ThreadTwo(object obj)
{
Thread.Sleep(600);
Lifecycle.Start();
}
}
class Engine
{
public void Start()
{
Console.WriteLine("Engine was started");
}
public void Stop()
{
Console.WriteLine("Engine was stopped");
}
}
static class Lifecycle
{
private static readonly object LockObject;
private static Engine Engine;
static Lifecycle()
{
LockObject = new object();
Engine = new Engine();
}
public static void Start()
{
lock (LockObject)
{
Engine.Start();
Thread.Sleep(800);
}
}
public static void Stop()
{
lock (LockObject)
{
Engine.Stop();
}
}
}
如果您的目标是多次调用
Start
,而实际上没有第二次启动,那么
private static bool _isStarted
public static void Start()
{
if(!_isStarted)
{
_isStarted = true;
...
}
}
// set to false in Stop()
这有一个竞争条件问题。我用简单变量给出了一个想法
如果你的目标是调用上一个,那么它就是这样实现的:
static int _counter;
// thread 1
Interlocked.Increment(ref _counter); // instead of start
... // sleep?
Incterlocked.Decrement(ref _counter); // instead of stop
// thread 2
Interlocked.Increment(ref _counter); // instead of start
... // sleep?
// after all threads are finished, check _counter
// positive - means Start()
现在,生命周期管理同步
using System;
using System.Threading;
class Program
{
static void Main(string[] args)
{
new Thread(ThreadOne).Start();
new Thread(ThreadTwo).Start();
Console.Read();
}
private static void ThreadOne(object obj)
{
Lifecycle.Start();
Thread.Sleep(500);
Lifecycle.Stop();
}
private static void ThreadTwo(object obj)
{
Thread.Sleep(600);
Lifecycle.Start();
}
}
class Engine
{
public void Start()
{
Console.WriteLine("{0:O} [{1}] Engine was started", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
}
public void Stop()
{
Console.WriteLine("{0:O} [{1}] Engine was stopped", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
}
}
static class Lifecycle
{
private static Engine Engine;
static Lifecycle()
{
Engine = new Engine();
}
public static void Start()
{
Monitor.Enter(Engine);
Engine.Start();
Thread.Sleep(800);
}
public static void Stop()
{
Engine.Stop();
Monitor.Exit(Engine);
}
}
为什么不直接访问监视器的方法来代替
锁
s
internal static class Lifecycle
{
private static Engine Engine;
static Lifecycle()
{
Engine = new Engine();
}
public static void Start()
{
Monitor.Enter(Engine);
Engine.Start();
Thread.Sleep(800);
}
public static void Stop()
{
Engine.Stop();
Monitor.Exit(Engine);
}
}
您希望最后发生的事情是线程2启动引擎?但是,在线程1执行
Stop
方法之前,线程2可以运行Start
。@YuvalItzchakov是的,它是。在本例中,它将启动发动机两次,然后停止发动机一次。你希望所有的动作都按顺序进行,而不是从外观上开始、停止、开始。在您的程序中,从来没有任何一个时间点,每个线程都应该同时执行某些操作,也不希望任何操作相互交织。因此,解决方案显然是删除所有附加线程,然后按顺序运行程序。您添加了大量线程开销,实际上没有任何好处。谢谢大家,您的答案,特别是删除的答案非常有用。不,目标是执行Start、Stop、Start,而不遗漏任何一项。我现在不知道您需要什么。在本例中,您在注释中说,它将启动发动机两次,然后停止发动机一次。而不是开始,停止,开始
,这让我觉得你是在用不必要的电话来应付日常开支。但是现在你声明你不想错过电话。你想让他们排队还是什么?@scott4dev-当然,你可以锁定生命周期
类型。但是,如果您出于某种原因需要多个锁,您不会希望这样做。@ChristopherCurrens MSFT他不建议您锁定生命周期。那是个糟糕的主意。他建议锁上引擎
,这很不一样。@Servy-谢谢,直到我看不懂为止。这更有意义,我看不出有多少人建议锁定类型(获得死锁情况的简单方法)。@christorcurrens MSFT现在您的解决方案与我的相同,您可以发布它later@scott4dev-我帮不了你(甚至不能删除它,因为它被标记为答案)。让OP替你做个记号。这些要点对我来说没有任何意义。