2016-11-30 1 views
2

Это первый случай, когда я пытался использовать потоки в приложении. Я знаю, что этот вопрос задавали раньше, но из решений, которые я рассматривал, я не вижу, как их применять в моей ситуации.C# Как проверить, что поток закончен, прежде чем запускать другой

У меня есть программа, где datagridview обновляется на таймере каждые 60 секунд. Данные поступают из базы данных SQL. Этот таймер также запускает рабочий поток для поиска конкретного устройства Bluetooth и обновления базы данных на основе его результатов в фоновом режиме. Поиск Bluetooth особенно медленный, поэтому я помещаю его в рабочий поток.

Моя проблема в том, что новый рабочий поток начинается до того, как предыдущий закончен. По крайней мере, это единственное логическое объяснение ошибок, которые я получаю. Большая отдача - это ошибка блокировки файла, когда единственной вещью, которая может блокировать файл, является другой рабочий поток из того же приложения.

Вот код, который я использую, чтобы начать фоновый поток.

private void timerScreenRefresh_Tick(object sender, EventArgs e) 
{ 
    if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", ""); 

    // If the user is not on a Remote desktop connection 
    if (!remoteDesktopUser) 
    { 

     // Run the Bluetooth Search in a worker thread 
     Thread thread = new Thread(new ThreadStart(this.checkProximity)); 
     thread.IsBackground = true; 
     thread.Start(); 
    } 

    // Load User Data from the DB and display on the screen 
    loadUserData(); 
} 

Казалось бы, что решение использовать thread.IsAlive(), но я не смог найти хороший пример. Кажется странным попытаться проверить существование потока, когда я только что создал новый, с «Thread thread = new Thread()»

Очевидно, что я что-то упустил. Я использую Visual Studio 2008. Спасибо за любые идеи Давид

UPDATE

на основе предлагаемого решения по krw12572 ниже я попытался это ...

Я изменил! = К ==, потому что я все еще хочу каждый раз запускать метод loadUserData() в основном потоке.

В редакторе я получаю зеленое подчеркивание на «_bluetoothSearchThread», сообщая мне, что поле никогда не назначается и всегда будет иметь значение NULL.

Во время выполнения я получаю сообщение об ошибке «Ссылка на объект, не установленное на экземпляр объекта» в этой строке.

Как это значение присваивается?

private Thread _bluetoothSearchThread; 
    private void timerScreenRefresh_Tick(object sender, EventArgs e) 
    { 
     if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", ""); 

     // Check if Worker Thread is already running. 
     if (_bluetoothSearchThread == null && _bluetoothSearchThread.IsAlive) 
     { 
      if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running"); 

      // If the user is not on a Remote desktop connection 
      if (!remoteDesktopUser) 
      { 
       // Check if the users mobile phone is within range 
       // Run the Bluetooth Search in a worker thread 

       Thread thread = new Thread(new ThreadStart(this.checkProximity)); 
       thread.IsBackground = true; 
       thread.Start(); 
      } 
     } 
     else 
     { 
      if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Worker Thread still running don't start another one"); 
     } 

     // Load User Data from the DB and display on the screen 
     loadUserData(); 
    } 

Update 2

OK Я думаю, что я понял это. Я изменил! = Нулевое обратно к тому, как оно было, и повернул IF и Else Around в другую сторону.

Тогда я должен был использовать мой мозг немного и изменил «нить», чтобы «_bluetoothSearchThread»

Теперь код компилируется и работает. Теперь мне просто нужно проверить его, вызвав условия, которые вызывают ошибку блокировки файлов, чтобы увидеть, действительно ли я исправил исходную проблему. Если это сработает, я отвечу krw12572 как правильно.

Обновление 2.5 я также должен был переместить эту линию так, что не создает новый экземпляр слишком рано

_bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity)); 

Так что это рабочий раствор.

private Thread _bluetoothSearchThread; 
    private void timerScreenRefresh_Tick(object sender, EventArgs e) 
    { 
     if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", ""); 


     // Check if Worker Thread is already running. 
     if (_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive) 
     { 
      // Thread is still running. Just log it and move on. 
      if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "******** Worker Thread still running don't start another one *********"); 
     } 
     else 
     { 
      if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", "Previous Worker Thread not running"); 

      // If the user is not on a Remote desktop connection 
      if (!remoteDesktopUser) 
      { 
       // Check if the users mobile phone is within range 
       // Run the Bluetooth Search in a worker thread 
       _bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity)); 
       _bluetoothSearchThread.IsBackground = true; 
       _bluetoothSearchThread.Start(); 
      } 
     } 

     // Load User Data from the DB and display on the screen 
     loadUserData(); 
    } 
+0

Здесь ваш результат: http://stackoverflow.com/questions/12949024/detecting-a-thread-is-already-running-in-c-sharp-net –

+0

@BALA Я видел это решение раньше. Это казалось слишком сложным, и я этого не понимал. Я постараюсь и слепо следовать за ним завтра и посмотреть, выходит ли что-то работоспособное. –

+0

Возможный дубликат [Как проверить завершение выполнения Thread] (http://stackoverflow.com/questions/2773479/how-to-check-if-thread-finished-execution) –

ответ

4

Если вы хотите только один поток, работающий в то время, то вы можете создать поле для хранения экземпляра Thread. С помощью этого экземпляра потока вы можете проверить, запущен ли он или нет, используя _threadInstance.IsAlive.

private Thread _bluetoothSearchThread; 
private void timerScreenRefresh_Tick(object sender, EventArgs e) 
{ 
    if(_bluetoothSearchThread != null && _bluetoothSearchThread.IsAlive) 
     return;  //It means one thread is already performing the search operation. 

    if (LocalUtilities.Debug > 3) LocalUtilities.writeLogFile(4, "Primary", LocalUtilities.getCurrentMethod() + "()", ""); 

    // If the user is not on a Remote desktop connection 
    if (!remoteDesktopUser) 
    { 

     // Run the Bluetooth Search in a worker thread 
     _bluetoothSearchThread = new Thread(new ThreadStart(this.checkProximity)); 
     _bluetoothSearchThread.IsBackground = true; 
     _bluetoothSearchThread.Start(); 
    } 

    // Load User Data from the DB and display on the screen 
    loadUserData(); 
} 
+0

Я пробовал это. У него были некоторые проблемы. Я обновил свой вопрос, чтобы включить предлагаемое решение и сообщения об ошибках. Спасибо David –

+0

Я обновил свой ответ. Вместо создания Thread thread = new Thread (..) используйте новое созданное поле для экземпляра потока. _bluetoothSearchThread = new Thread (...) –

4

EDIT:

после исследования, используя Thread.IsAlive в вашем situtation не является безопасным способом сделать это.

Вы должны использовать Threa.Join()

Документация:

Блокирует вызывающий поток, пока поток, представленный этим экземпляр не прекращается или указанное время истечет, продолжая выполнять стандартные COM и SendMessage насосное.

Пример:

while(!currentThread.Join(0)) //should specify the time if you dont want it to be blocking. 
{ 
    ///thread is ongoing 
} 
Console.WriteLine("while loop has breaked! so the thread is finished!"); 
+0

Как использовать Thread.IsAlive в моем примере кода. Не могли бы вы дать мне несколько идей? –

+0

@DavidPollard 'if (thread.isAlive) // то делать что угодно; ' –

+0

@DavidPollard привет, я только что отредактировал aswer –

0

Вы можете использовать Task вместо Thread.

// Create dummy task 
Task task = Task.Run(() => { }); 

private void timerScreenRefresh_Tick(object sender, EventArgs e) 
{ 
    ... 
    // add continuation to current task 
    task.ContinueWith(t => checkProximity); 
    ... 
} 

Новая задача будет выполнена только после предыдущего.

Однако, если задачи не имеют времени для запуска во время Tick, они будут накапливаться в очереди.

+0

Привет, Александр, я думал о задачах в качестве альтернативы, хотя нет никакого смысла во мне стоять в очереди под задачи. Теперь я понимаю, что предлагает krw12572, и мои решения выше работают. Чтобы проверить, я установил свой таймер на 10 секунд, и я мог видеть из своих журналов, что он открывал и закрывал потоки повсюду. С приведенным выше кодом на месте хорошо и аккуратно. Тема 11 Начинается, и ничего не начинается до тех пор, пока не будет завершен поток 11. Поэтому любые другие ошибки, которые я получаю сейчас, не связаны с перекрывающимися потоками. Спасибо за ваши идеи. Дэвид –

Смежные вопросы