如何在给定点停止线程?

时间:2021-06-17 07:12:04

I was trying to stop some threads, read some things about the proper way to do it gracefully, but I must be doind something wrong because it simply doesn't work. At first I tried without the lock() with _IsRunning being volatile, then tried with the locks. Here is what I've got.

我试图阻止一些线程,阅读一些关于正确地做到这一点的正确方法的事情,但我必须做错了,因为它根本不起作用。起初我尝试没有lock(),_IsRunning是易失性的,然后尝试使用锁。这就是我所拥有的。

private volatile bool _IsRunning;
private static readonly object runLock = new object();

public void Start()
{
    if (_IsRunning == true)
        return;
    _IsRunning = true;
    (new System.Threading.Thread(new System.Threading.ThreadStart(SendLoop))).Start();
}

public void Stop()
{
    lock (runLock)
    {
        _IsRunning = false;
    }
}

private void SendLoop()
{
    while (_IsRunning)
    {
        lock (runLock)
        {
            if (_sockets.Count > 0)
            {
                //some stuff
            }
            else
            {
                System.Threading.Thread.Sleep(10);
            }
        }
    }
}

I set a breakpoint at my while(), and _IsRunnig is still true even though I passed in Stop().

我在while()处设置了一个断点,即使我传入了Stop(),_IsRunnig仍然是真的。

2 个解决方案

#1


The lock is required here because of the way your start method is written, however, you only need the lock in Start() (where it isn't now) and Stop(), since they're the only ones that could potentially cause a race condition in your case.

由于你的start方法的编写方式,这里需要锁定,但是,你只需要Start()(现在不是)和Stop()的锁,因为它们是唯一可能导致的在你的情况下的竞争条件。

I would remove the lock from your SendLoop() method entirely (it's causing a DeadLock since Stop is waiting on the lock to set _isRunning, and your SendLoop is holding the lock until _isRunning is set to false). Right now, when you call Stop(), the lock is preventing it from ever setting _isRunning = false;

我会完全从你的SendLoop()方法中删除锁(它导致死锁,因为Stop正在等待锁设置_isRunning,而你的SendLoop持有锁,直到_isRunning设置为false)。现在,当你调用Stop()时,锁定会阻止它设置_isRunning = false;

However, you will need locks in your Start() and Stop() methods (unless you rework the way they are structured entirely). Something like:

但是,您需要在Start()和Stop()方法中使用锁定(除非您按照完全构造的方式进行返工)。就像是:

public void Start()
{
    lock (runLock)
    {
        if (_IsRunning == true)
            return;
        _IsRunning = true;
        (new System.Threading.Thread(new System.Threading.ThreadStart(SendLoop))).Start();
    }
}

public void Stop()
{
    lock (runLock)
    {
        _IsRunning = false;
    }
}

This will protect you from starting 2 threads, and will also keep Stop from stopping before the thread has started.

这将保护您免于启动2个线程,并且还将在线程启动之前阻止Stop停止。

#2


You need to reorganize your loop a little bit. Right now you are holding the lock on runLock for a very long period of time. This will cause anyone calling the Stop method to hang until the if block succeeds or the Sleep call returns. This can lead to issues because you cannot look at _isRunning when the Stop method is called, only when it returns. Try reorganizing your code as follows

你需要稍微重新组织你的循环。现在你在runLock上持有很长一段时间的锁定。这将导致任何调用Stop方法的人挂起,直到if块成功或Sleep调用返回。这可能会导致问题,因为只有在返回时,才能在调用Stop方法时查看_isRunning。尝试按如下方式重新组织代码

private void SendLoop() {
  do {
    if ( _sockets.Count > 0 ) {
    } else { 
      System.Threading.Thread.Sleep(10);
    }
    bool shouldContinue;
    lock ( runLock ) { 
      shouldContinue = _IsRunning;
    }
  while(shouldContinue);
}

I'm not 100% sure this is the issue. But at least it should help clear things up a bit.

我不是100%肯定这是问题所在。但至少它应该有助于清理一些事情。

#1


The lock is required here because of the way your start method is written, however, you only need the lock in Start() (where it isn't now) and Stop(), since they're the only ones that could potentially cause a race condition in your case.

由于你的start方法的编写方式,这里需要锁定,但是,你只需要Start()(现在不是)和Stop()的锁,因为它们是唯一可能导致的在你的情况下的竞争条件。

I would remove the lock from your SendLoop() method entirely (it's causing a DeadLock since Stop is waiting on the lock to set _isRunning, and your SendLoop is holding the lock until _isRunning is set to false). Right now, when you call Stop(), the lock is preventing it from ever setting _isRunning = false;

我会完全从你的SendLoop()方法中删除锁(它导致死锁,因为Stop正在等待锁设置_isRunning,而你的SendLoop持有锁,直到_isRunning设置为false)。现在,当你调用Stop()时,锁定会阻止它设置_isRunning = false;

However, you will need locks in your Start() and Stop() methods (unless you rework the way they are structured entirely). Something like:

但是,您需要在Start()和Stop()方法中使用锁定(除非您按照完全构造的方式进行返工)。就像是:

public void Start()
{
    lock (runLock)
    {
        if (_IsRunning == true)
            return;
        _IsRunning = true;
        (new System.Threading.Thread(new System.Threading.ThreadStart(SendLoop))).Start();
    }
}

public void Stop()
{
    lock (runLock)
    {
        _IsRunning = false;
    }
}

This will protect you from starting 2 threads, and will also keep Stop from stopping before the thread has started.

这将保护您免于启动2个线程,并且还将在线程启动之前阻止Stop停止。

#2


You need to reorganize your loop a little bit. Right now you are holding the lock on runLock for a very long period of time. This will cause anyone calling the Stop method to hang until the if block succeeds or the Sleep call returns. This can lead to issues because you cannot look at _isRunning when the Stop method is called, only when it returns. Try reorganizing your code as follows

你需要稍微重新组织你的循环。现在你在runLock上持有很长一段时间的锁定。这将导致任何调用Stop方法的人挂起,直到if块成功或Sleep调用返回。这可能会导致问题,因为只有在返回时,才能在调用Stop方法时查看_isRunning。尝试按如下方式重新组织代码

private void SendLoop() {
  do {
    if ( _sockets.Count > 0 ) {
    } else { 
      System.Threading.Thread.Sleep(10);
    }
    bool shouldContinue;
    lock ( runLock ) { 
      shouldContinue = _IsRunning;
    }
  while(shouldContinue);
}

I'm not 100% sure this is the issue. But at least it should help clear things up a bit.

我不是100%肯定这是问题所在。但至少它应该有助于清理一些事情。