Как запустить поток, если нажатая кнопка и останавливает его, если нажато снова?

В целом я нашел, что использование, TBB требует намного большего количества трудоемких изменений в кодовой базе с высокой выплатой, в то время как OpenMP дает быструю, но умеренную выплату. Если Вы смотрите новый модуль с нуля и думаете долгосрочное движение с TBB. Если Вы хотите маленькие но непосредственные усиления, идут с OpenMP.

кроме того, TBB и OpenMP не являются взаимоисключающими.

6
задан Kiquenet 4 May 2013 в 12:37
поделиться

3 ответа

Одна из проблем этого подхода состоит в том, что очень опасно произвольно прерывать поток (практически на любом языке). Слишком много проблем, которые могут возникнуть из-за неиспользованных ресурсов и неправильно удерживаемых блокировок. Как правило, лучше всего установить какой-либо флаг, чтобы попросить поток безопасно прервать себя или забыть о потоке и позволить ему работать до завершения.

Кроме того, прерывание потока в пуле потоков очень опасно, и я считаю, что эта операция не поддерживается. Потоки в ThreadPool не принадлежат вам, и их холодное прерывание имеет серьезные последствия для ThreadPool.

Вот решение, которое я бы выбрал.

private object m_lock = new object();
private bool m_isRunning = false;
private bool m_isAbortRequested = false;

public void OnButtonClick(object sender, EventArgs e) {
  lock ( m_lock ) {
    if ( m_isRunning ) {
      m_isAbortRequested = true;
    } else {
      m_isAbortRequested = false;
      m_isRunning = true;
      ThreadPool.QueueUserWorkItem(BackgroundMethod);
    }
  }
}

private void BackgroundMethod() {
  try {
    DoRealWork();
  } finally {
    lock (m_lock) {
      m_isRunning = false;
    }
  }
}

private void DoRealWork() {
  ...
  if ( m_isAbortRequested ) {
    return;
  }
}
10
ответ дан 8 December 2019 в 14:44
поделиться

Да, это очень неправильно. Никогда не следует пытаться вручную управлять потоком ThreadPool . Если вам нужен такой контроль, вы должны использовать свой собственный объект Thread . Кроме того, Abort () не рекомендуется для завершения потока; у вас должен быть элемент управления volatile bool в вашей форме, который код в MethodToCall проверяет в различных точках и корректно завершает работу, когда он истина . Хотя вы можете использовать тот же подход с ThreadPool , тот факт, что вам нужно иметь возможность отменить, по-видимому, указывает на то, что процесс выполняется долго или, по крайней мере, имеет потенциал. ThreadPool не следует использовать для длительно выполняемых процессов.

Например ...

private volatile bool stopThread = false;
private Thread workThread;

private void StartThread()
{
    if(workThread == null)
    {
        stopThread = false;
        workThread = new Thread(new ThreadStart(MethodToCall));

        workThread.Start();
    }
}

private void StopThread()
{
    if(workThread != null)
    {
        stopThread = true;

        workThread.Join(); // This makes the code here pause until the Thread exits.

        workThread = null;
    }
}

Затем в MethodToCall просто проверяйте логическое значение stopThread через частые промежутки времени и выполняйте любые необходимые действия по очистке и выйдите из метода. Например ...

private void MethodToCall()
{
    // do some work here and get to a logical stopping point

    if(stopThread)
    {
        // clean up your work

        return;
    }

    // do some more work and get to another stopping point

    if(stopThread)
    {
        // clean up your work

        return;
    }
}

И просто повторите этот шаблон.

3
ответ дан 8 December 2019 в 14:44
поделиться

В ситуациях, когда одному потоку нужно «сигнализировать» другому потоку, чтобы что-то сделать, я обычно использую System.Threading.ManualResetEvent, чтобы сигнализировать второстепенному потоку об остановке, например:

private volatile bool _threadRunning = false;
private ManualResetEvent _signal = new ManualResetEvent(false);
private Thread _thread;
private void OnButtonClick(object sender, EventArgs e)
{
    if (!_threadRunning) {
        // Reset the 'signal' event.
        _signal.Reset();
        // Build your thread parameter here.
        object param = ;
        // Create the thread.
        _thread = new Thread(ExecuteThreadLogicConditionally(param));
        // Make sure the thread shuts down automatically when UI closes
        _thread.IsBackground = true;
        // Start the thread.
        _thread.Start();
        // Prevent another thread from being started.
        _threadRunning = true;
    } else {
        // Signal the thread to stop.
        _signal.Set();
        // DO NOT JOIN THE THREAD HERE!  If the thread takes a while
        // to exit, then your UI will be frozen until it does.  Just
        // set the signal and move on.
    }
}
// If the thread is intended to execute its logic over and over until
// stopped, use this callback.
private void ExecuteThreadLogicUntilStopped(object param)
{
    // Use a while loop to prevent the thread from exiting too early.
    while (!_signal.WaitOne(0)) {
        // Put your thread logic here...
    }
    // Set the flag so anther thread can be started.
    _threadRunning = false;
}
// If the thread logic is to be executed once and then wait to be
// shutdown, use this callback.
private void ExecuteThreadLogicOnce(object param)
{
    // Put your thread logic here...
    //
    // Now wait for signal to stop.
    _signal.WaitOne();
    // Set the flag so another thread can be started.
    _threadRunning = false;
}
// If the thread needs to be stopped at any point along the way, use
// this callback.  The key here is to 'sprinkle' checks of the 'signal'
// to see if the thread should stop prematurely.
private void ExecuteThreadLogicConditionally(object param)
{
    if (_signal.WaitOne(0)) { _threadRunning = false; return; }
    // Execute small chunk of logic here...
    if (_signal.WaitOne(0)) { _threadRunning = false; return; }
    // Execute another small chuck of logic here...
    if (_signal.WaitOne(0)) { _threadRunning = false; return; }
    // Continue this pattern through the method.
}

Примечание что это решение вообще не использует ThreadPool. Это легко сделать. И в качестве предложения я бы не стал гадать с функцией SetMaxThreads () в ThreadPool. Просто позвольте ThreadPool делать свое дело. Он был разработан с учетом того, как вы его используете.

2
ответ дан 8 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: