Насколько критична блокировка - степень и способы отказа - PullRequest
0 голосов
/ 09 января 2012

Я стресс-тестировал приведенный ниже код, и он, кажется, работает нормально - каковы опасности не блокирования в простом случае, когда запись одного потока выполняется, а отдельный поток читает простую переменную?

Есть класс, который имеет публичную собственность ...

Public Class PropHolder
    Private _myVar As Double
    Public Property myVar() As Double
        Get
            Return _myVar
        End Get
        Set(ByVal value As Double)
            _myVar = value
        End Set
    End Property
End Class

... и другой, который использует экземпляр этого класса

Public Class Form1 

Public _propHolder As New PropHolder
Delegate Sub dlgPostVar()

    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        While Not BackgroundWorker1.CancellationPending
            _propHolder.myVar = someValue  'worker thread writing var
        End While
    End Sub

    Private Sub BackgroundWorker2_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
        While Not BackgroundWorker2.CancellationPending
            Me.Invoke(New dlgPostVar(AddressOf postVal)) 'invoke UI thread to write var
        End While
    End Sub

    Private Sub postVal()
        RichTextBox1.AppendText(_propHolder.myVar.ToString & vbCrLf)
    End Sub

End Class

В приведенном выше примере myVar непрерывно меняется и записывается в RichTextBox так быстро, как может поддерживать UI. Не все значения фиксируются, но это не важно - давайте представим, что RichTextBox заботится только о выборке текущего значения myVar в свободное время.

Все, что я прочитал, наводит меня на мысль, что это небезопасно, но мне еще предстоит сделать его неудачным, даже когда две переменные читают и пишут (один читатель, один писатель) эту переменную непрерывно. Что может пойти не так и почему?

Редактировать: Чтобы быть более конкретным, этот вопрос скорее гипотетический, чем практический. Я знаю, что эта ситуация требует блокировки «по книге», вопрос состоит в том, чтобы исследовать широту потенциальных последствий отсутствия блокировки в этом случае, возможно, в виде полного набора всех возможных способов отказа.

Одним из примеров, таким образом, является чтение из переменной, записываемой в:

  • Тема 1 -> Читает младшее слово из памяти
  • Thread 2 -> CPU перемещает младшее слово нового значения в память
  • Thread 2 -> CPU перемещает старшее слово нового значения в память
  • Тема 1 -> Читает старшее слово из памяти

Значение потока 1 теперь (HighWord [новое]) (LowWord [старое]) ** повреждено

Ошибка программы ограничена повреждением, вызванным обработкой этого поврежденного значения. Другие последствия этого режима отказа? Есть ли?

Дополнительные примеры? Книги / ссылки приветствуются.

Редактировать # 2: Мое намерение здесь состоит в том, чтобы исследовать в среде .NET степень и форму непредсказуемости и ошибок, которые свойственны платформе и конкретно не связаны с последствиями того, как любая конкретная программа может впоследствии потерпеть неудачу. лицо такой ошибки.

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

Ответы [ 3 ]

3 голосов
/ 09 января 2012

В этом случае вам нужна блокировка, поскольку запись переменных в double не является атомарной.Следовательно, это может сломаться, просто крайне маловероятно.

0 голосов
/ 09 января 2012

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

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

Есть веская причина, по которой у каждого класса в MSDN есть документация по безопасности потоков.Microsoft относится к этому серьезно, как и вы.

0 голосов
/ 09 января 2012

То, что вы тестируете, не вызывает проблем, не означает, что их не произойдет.Проблемы с потоками труднее всего отлаживать.Причиной блокировки кода является предотвращение устаревания информации или двойная обработка.Возможны следующие проблемы: один поток устанавливает значение, а затем другой переопределяет его, не позволяя обработать его.В вашем случае вы можете столкнуться с проблемой, когда она в данный момент записывает данные в переменную, поскольку другой поток читает из нее, вызывая проблему.

Из MSDN:

"Все члены этого типа являютсяПотокобезопасный. Члены, которые, по-видимому, изменяют состояние экземпляра, фактически возвращают новый экземпляр, инициализированный новым значением. Как и в случае любого другого типа, чтение и запись в общую переменную, содержащую экземпляр этого типа, должны быть защищены блокировкой, чтобы гарантировать потокsafety.

Осторожно

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

"

...