简体   繁体   中英

How to terminate/exit/abort old thread workers and restart program?

I have these control buttons (Windows.Forms):

Start/Restart | Pause | Continue

Once Start is pressed, threadPool[workerThreadsCount] is created, ManualResetEvent mre is set to mre.Set() and threads start doing their job. In some pseudo-code:

threadStartingPoint() {
int index = 0;
while(index !== someMaxCondition)
      ... // grab some data to work on
      lock(_lock) {  // lock index, so one access at a time
        index += index;
      }
      ... // do some stuff
      _mre.WaitOne(); // Pause if button Pause is pressed.
    }
}

Worker threads work in a loop like in example above. Now if I press pause , everything stop at _mre.Wait(); position. With continue I can open gates using mre.Set() and everything works just fine. Now the problem is when I Pause , I want user to choose between Continue or Restart . The problem with Restart is that I have no idea how to tell my threads to exit that while loop . Because If I just set mre.Set() and create new threads, for some time the old ones will still work with that old data loop.

Any suggestions?

Pass in a CancellationToken and have it checked each loop.

private volatile CancellationTokenSource _tokenSource = new CancellationTokenSource();

threadStartingPoint() {
int index = 0;
var token = _tokenSource.Token;
while(index !== someMaxCondition && !token.IsCancellationRequested)
      ... // grab some data to work on
      lock(_lock) {  // lock index, so one access at a time
        index += index;
      }
      ... // do some stuff
      _mre.WaitOne(); // Pause if button Pause is pressed.
    }
}

When the user clicks the Cancel button have it send a Cancel to the CancellationTokenSource the tokens are derived from. Then new workers can just use a new Token Source that are unaffected by the previous cancelation.

private void ButtonCancelClick(object sender, EventArgs e)
{
    //Get a local copy of the source and replace the global copy
    var tokenSource = _tokenSource;
    _tokenSource = new CancellationTokenSource();

    //Cancel all loops that used the old token source
    tokenSource.Cancel();
    mre.Set();
}

The "by the book" answer is to consider implementing a CancellationTokenSource .

But, if you already have working code, I would just add a variable bool restartRequested=false; .

When the user then requests a restart, set restartRequested=true; and reset the _mre . Then break the while loop and let the thread method complete, if restartRequested==true .

You could create another ManualResetEvent that gets set only when the "Restart" button is clicked. Here's the updated code using the new WaitHandle.

threadStartingPoint() {
int index = 0;
//We have two waithandles that we need to wait on
var waitHandles = new WaitHandle[] {_mre, _restartMre};
while(index !== someMaxCondition)
      ... // grab some data to work on
      lock(_lock) {  // lock index, so one access at a time
        index += index;
      }
      ... // do some stuff

      //Wait on any one of the wait handles to signal
      WaitHandle.WaitAny(waitHandles);
      if (_restartMre.WaitOne(0)){
          break;
      }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM