2015-03-26 8 views
4

Я работаю над библиотекой классов, которая обеспечит асинхронную связь с приложениями CLR.Почему SyncLock здесь не работает?

В SslStream есть асинхронные чтения (BeginRead) с единой процедурой обратного вызова, разделяемой несколькими потоками. Я не хочу, чтобы обратные вызовы обрабатываются параллельно во время отладки, поэтому я создал критическую секцию:

Private Sub Callback_Read(ByVal ar As IAsyncResult) 
    Static OneAtATime As New Object 
    SyncLock OneAtATime 
     Dim ThisSslStream As SslStream = DirectCast(ar.AsyncState, SslStream) 
     ... 
    End SyncLock 
End Sub 

К моему удивлению, что не работает, по крайней мере, когда я поставил точку останова в пределах Блок SyncLock. Обратные вызовы для нескольких потоков запускаются внутри него в одно и то же время, не дожидаясь в точке входа, пока предыдущий поток не покинет его.

Одиночный шаг - это кошмар, особенно когда потоки закрываются (закрываются) одновременно: выполнить линию для потока 1, выполнить линию для потока 2, выполнить следующую строку для 1, выполнить следующую строку для 2 и т. Д. , через весь блок.

Я подумал, может быть, вам нужно что-то большее, чем просто общий «новый объект», но потом я увидел, что на переполнении стека есть хотя бы один ответ, который иллюстрирует SyncLock точно так же, как я его использую, с помощью только «Static X как «Новый объект» для создания объекта синхронизации внутри функции, которая должна быть заблокирована.

Это потому, что обратный вызов на самом деле происходит из потока win32 вне .Net framework, который SyncLock здесь не работает?

+0

Является ли метод всегда вызываться на одном объекте или через отдельные объекты этого типа? –

+0

VB.NET не использует «статический», но общий. Также попробуйте переместить объект блокировки вне области действия метода. –

+1

@ AllanS.Hansen Неправильно. VB.NET позволяет использовать модификатор 'Static' для локальных переменных, как это делал VB6. –

ответ

2

Я никогда не видел использования локальных переменных static в VB. То, что такая вещь существовала, была для меня новостью. Я бы предположил, что вы делаете это обычным способом и используете переменную класса shared.

public Class Test 
    Private shared SyncRoot As Object = new Object() 

    Private Sub Callback_Read(ByVal ar As IAsyncResult) 
     SyncLock SyncRoot 
     Dim ThisSslStream As SslStream = DirectCast(ar.AsyncState, SslStream) 
     ... 
     End SyncRoot 
    End Sub 

End Class 
+0

Я уже пробовал это тоже, не имеет значения. –

+0

Ой, забыл сделать его общим, когда я переместил его из функции. –

8
Static OneAtATime As New Object 

Статический ключевое слово было довольно тяжелым бременем на шее у реализаторов VB.NET. Они имели, чтобы поддерживать его, потому что он часто использовался в предыдущих выпусках Visual Basic, и его отсутствие приводило к слишком большим трудностям для программистов, которые хотят обновить свои инструменты.

Но его прежнее поведение было очень несовместимо с потоковой обработкой, которая очень сильно поддерживается в .NET. Не проблема, потому что старые версии VB не поддерживали создание потоков. Сумма кода MSIL, сгенерированного для этого оператора, составляет массивный. Вы должны взглянуть с помощью утилиты ildasm.exe.

Это массивное из-за того, что ему нужно делать. Которая инициализирует переменную только один раз, при первом вводе метода. Не очень сложно, он автоматически генерирует другую Boolean переменную, которая отслеживает. Но сложнее всего сделать это один раз для каждого отдельного потока. Другими словами, он имеет поведение [ThreadStatic].

Это то, что убивает вас здесь, каждая нить имеет свой собственный SyncLock. Вот почему вы не наблюдали никакой синхронизации вообще :) Вам нужно вывести его из метода и объявить его Shared.

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