访问共享资源时,通过静态锁进行线程同步

本文关键字:线程 同步 静态 共享资源 访问 | 更新日期: 2023-09-27 18:14:32

我试图修复一个问题,线程同步从两个线程都访问一个资源。在本例中,该资源是Engine

这里两个启动器正在启动引擎,其中一个线程正在停止它。目标是获得引擎启动的最终结果

澄清:我不控制ThreadOne/ThreadTwo中的代码,并且需要在Lifecycle类中进行同步。

在这个例子中,实现这一点的最好方法是什么?

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();
        }
    }
}

访问共享资源时,通过静态锁进行线程同步

为什么不直接访问Monitor的方法来代替lock 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);
    }
}

如果您的目标是多次调用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()

现在Lifecycle管理同步

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);
    }
}