2013-07-23 4 views
0

Я знаю, что Thread.Abort() не совсем безопасно, но я не могу себе представить, что это может привести в случае ниже:Как избежать Thread.Abort() в этом случае?

Private threadLoadList As Thread 

Private Sub LoadList(ByVal argument As Integer) 

    Try 
     Refresh_Grid(GET_DATA(argument), argument) 'Fills grid with data loaded from database 
     Change_Cursor() 'Changes cursor to Cursor.Default 
    Catch ex As ThreadAbortException 
     'Do nothing 
    Catch ex As Exception 
     Error_log(ex.Message) ' Saves ex.Message in database 
    End Try 

End Sub 

Private Sub SomeValueChanged(sender As Object, e As EventArgs) Handles Control.ValueChanged 
    If Not threadLoadList Is Nothing Then 
     If threadLoadList.IsAlive Then 
       threadLoadList.Abort() 
     End If 
    End If 
    Cursor = Cursors.WaitCursor 
    threadLoadList = New Thread(AddressOf LoadList) 
    threadLoadList.Start(1) 
End Sub 

Как вы можете видеть, пользователь может изменить некоторые значения (ComboBox) и в результате изменить содержимое сетки. Функция GET_DATA() занимает около 10 секунд, таким образом, возможно, что пользователь изменит значение Combobox до обновления сетки - вот почему ранее начатый поток убит.

Опасно ли это? Если да, можете ли вы предложить какое-то другое решение?


Хорошо, я понимаю;). Я стараюсь, чтобы избежать тайм-аута (в некоторых случаях запрос выполняется менее 1 секунды) Это лучшее решение:

Private threadLoadList As Thread 
Private Changed As Boolean = False 

Private Sub LoadList(ByVal argument As Integer) 

    Try 
     Dim dt As DataTable = GET_DATA(argument) 
     'Enter Monitor 
     If Changed Then 
      Return 
     End IF 
     'Exit Monitor 
     Refresh_Grid(dt, argument) 'Fills grid with data loaded from database 
     Change_Cursor() 'Changes cursor to Cursor.Default 
     'Enter Monitor 
      Changed = False 
     'Exit Monitor 
    Catch ex As ThreadAbortException 
     'Do nothing 
    Catch ex As Exception 
     Error_log(ex.Message) ' Saves ex.Message in database 
End Try 

End Sub 

Private Sub SomeValueChanged(sender As Object, e As EventArgs) Handles Control.ValueChanged 
    'Enter Monitor 
     Changed = True 
    'Exit Monitor 
    Cursor = Cursors.WaitCursor 
    Dim t As Thread = New Thread(AddressOf LoadList) 
    t.Start(1) 
End Sub 
+1

Да, это опасно. Что, если AbortException происходит внутри предложения finally внутри Refresh_Grid()? –

ответ

1

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

Что касается использования Thread.Abort, то да; это опасно. Это опасно в том смысле, что ваше приложение будет генерировать исключение, испорченные данные, сбой, разрыв в пространстве-времени и т. Д. Есть все виды отказов, которые можно ожидать от прерывания потока. Лучшим решением является использование протокола прекращения совместной работы вместо того, чтобы выполнять жесткое прерывание. Обратитесь к моему ответу here за краткое введение в действительные подходы.

+0

Спасибо, Брайан, Не беспокойтесь о потоке пользовательского интерфейса - я знаком с проблемой, и я знаю, как использовать InvokeRequired и т. Д. Наконец, я использовал какой-то механизм «Опрос механизма остановки», аналогичный тому, который представлен в мой отредактированный пост: после запроса к базе данных я проверяю, ожидает ли результат - если нет, я немедленно завершу поток через Return. В противном случае поток продолжит выполнение внутри монитора, поэтому приложение не содержит условия гонки. –