避免用锁启动新线程

时间:2018-12-19 09:41:31

标签: c# locking

是否可以为一个线程锁定方法并迫使另一个线程继续运行,而不是等到第一个线程完成?可以使用静态线程或某种适当的模式(在服务下面提到一个实例)解决此问题。

出于演示目的,可以使用如下所示的静态布尔值来完成。

public class SomeService
{
  private readonly IRepository _repo;
  public SomeService(IRepository repo)
  {
    _repo = repo;
  }

  private Thread threadOne;

  public static bool isLocked { get; set; }

  public void StartSomeMethod()
  {
    if(!isLocked)
    {
      threadOne = new Thread(SomeMethod);
      isLocked = true;
    }
  }

  public void SomeMethod()
  {
    while(true)
    {
      lots of time
    }
    ...
    isLocked = false;
  }
}

我想避免用户无意中单击两次以启动并在第一次完成后立即意外启动第二个线程的情况。

3 个答案:

答案 0 :(得分:1)

您可以使用锁:)

object locker = new object();
void MethodToLockForAThread()
{
    lock(locker)
    {
      //put method body here
    }
}

现在的结果是,当线程(任何线程)调用此方法时,它将在锁的开头放置类似于flag的内容:“ STOP!不允许进一步操作,必须等待!”就像十字路口的红灯一样。 当线程首先调用此方法时,先离开作用域,然后在作用域的开头,此“红灯”变为绿色。

如果您不想在另一个线程已经调用该方法时不调用该方法,则唯一的方法是使用bool值。例如:

object locker = new object();
bool canAccess = true;
void MethodToLockForAThread()
{
    if(!canAccess)
      return;

    lock(locker)
    {
      if(!canAccess)
        return;

      canAccess = false;            

      //put method body here

      canAccess = true;
    }
}

在锁定范围内对canAccess进行的其他检查是因为注释中已告知。不,它确实是线程安全的。这种保护在线程安全单例中很明显。

编辑

在与mjwills进行讨论之后,我不得不改变主意,将更多内容变为Monitor.TryEnter。您可以这样使用它:

object locker = new object();
void ThreadMethod()
{
  if(Monitor.TryEnter(locker, TimeSpan.FromMiliseconds(1))
  {
     try
     {
       //do the thread code
     }
     finally
     {
       Monitor.Exit(locker);
     }
  } else
    return; //means that the lock has not been aquired
}

现在,由于某些异常或某些其他线程已经获得了锁定,因此无法获得锁定。在第二个参数中,您可以传递线程等待获取锁的时间。我在这里花了很短的时间,因为您不希望其他线程在第一次执行此操作时就执行此操作。 因此,此解决方案似乎是最好的。

当另一个线程无法获取锁时,它将继续执行而不是等待(嗯,它将等待1毫秒)。

答案 1 :(得分:0)

您可以使用AutoResetEvent代替isLocked标志。

AutoResetEvent autoResetEvent = new AutoResetEvent(true);
public void StartSomeMethod()
{
    if(autoResetEvent.WaitOne(0))
    {
        //start thread
    }
}

public void SomeMethod()
{
    try
    {
        //Do your work
    }
    finally
    {
        autoResetEvent.Set();
    }
}

答案 2 :(得分:0)

由于lockMonitor类的特定语言包装器,因此您需要Monitor.TryEnter

public class SomeService
{
    private readonly object lockObject = new object();

    public void StartSomeMethod()
    {
        if (Monitor.TryEnter(lockObject))
        {
            // start new thread
        }
    }

    public void SomeMethod()
    {
        try
        {
            // ...
        }
        finally
        {
            Monitor.Exit(lockObject);
        }
    }    
}