Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Метод с тайм-аутом. Проблема взаимодействия с глобальными функциями и объектами.

63K
28 января 2011 года
Metallord
9 / / 09.12.2010
Есть экземпляр класса Core. В процедуре Main консольного приложения, вызываем Core.UpdateData.
В проекте используется внешняя библиотека, работа с её объектами производится в ф-ии DataRequest.
Если вызывать DataRequest в оснвном потоке (вставить её в цикл For Each метода UpdateData, то всё работает). Но ф-ия может долго выполняться и мне необходимо реализовать для неё принудительное завершение по тайм-ауту. Написал код. который приведен, ниже. Перестала вызываться ф-ия MyExternalDLL.ReadData(p_KEY), полагаю из-за того что она стала выполняться в отдельном потоке. Насколько, я знаю работать с объектами из основного потока, в дочерних нельзя. :rolleyes: Нужно сделать Invoke. Попытался через Reflection вызвать DataRequest, но всё равно не работает.
Подскажите поджалуйста как правильно сделать. :confused:

Код:
Imports System.Threading
Imports System.Reflection

Module modMain

Private WithEvents Core as clsCore=new clsCore

<STAThread()> Sub Main()
        Do While Not Console.KeyAvailable
            Core.UpdateData() 'Обновление данных
            Application.DoEvents()
        Loop
End Sub

End Module


Public Class clsCORE
        Private Key As String = ""
        Public Sub UpdateData()
                 For Each Key In CNC.Keys
                        Method()
                 Next
        End Sub

        Private Sub Method()
                Const TimeOut As Int32 = 1000
                Dim [handles] As WaitHandle() = New WaitHandle() {New AutoResetEvent(False)}
                ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf Worker), [handles](0))
                Dim finished As Boolean = WaitHandle.WaitAll([handles], TimeOut, True)
                If finished Then
                        Console.WriteLine("Worker function finished sucessfully")
                Else
                    Console.WriteLine([String].Format("Worker function time out({0})!", TimeOut))
                End If
        End Sub

        Private Sub Worker(ByVal state As Object)
                Dim are As AutoResetEvent = DirectCast(state, AutoResetEvent)
                Dim MyType As Type = GetType(clsCORE)
                Dim MyMethodInfo As MethodInfo = MyType.GetMethod("DataRequest")

                Dim MyInstance As Object = Activator.CreateInstance(MyType)
                Dim args() As Object = New Object() {Me.Key}
                Dim Value As Object = MyMethodInfo.Invoke(Core, args)
                Console.WriteLine(Value.ToString)
                are.[Set]()
        End sub

        Public Function DataRequest(ByVal p_KEY As String) As Object
                Return MyExternalDLL.ReadData(p_KEY)
        End Function
End Class
5
28 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Metallord

Подскажите поджалуйста как правильно сделать. :confused:


TPL + Cancellation.

63K
28 января 2011 года
Metallord
9 / / 09.12.2010
Спасибо! Я не в ту сторону копал. :)
63K
28 января 2011 года
Metallord
9 / / 09.12.2010



Попробовал не получилось, в Task action функция MyExternalDLL.ReadData(p_KEY) тоже возвращает 0. Т.к. Task выполняется повидимому тоже в отдельном потоке.

Подскажите пожалуйста какие классы фреймворка использовать чтобы решить мою задачу.

Пока я вижу только одно решение не использовать внешние объекты, объявить их внутри процедуры Worker и отдавать данные наверх (этот вариант не подходит, т.к. необходимо каждый раз коннектиться к оборудованию внутри Worker).

Я также пробовал решить эту задачу через System.Threading.Tasks (TPL + Cancellation) и в этом случае Return MyExternalDLL.ReadData(p_KEY) тоже возвращает 0.

Мне необходимо написать сервер, который рассылает киентам параметры полученные с оборудования по сети:

1.Клиент-сервер я написал
2.В сервере необходимо подключиться к удалённому оборудованию (это занимает время).
3.В сервере в цикле обновляю параметры оборудования, связь ненадёжная поэтому, чтобы сервер не подвисал нужно ввести отмену считывания параметра по тайм-ауту.
4.По завершению цикла клиентам разрешается получение данных.
Как реализовать 3. другим способом ? :confused:

5
29 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Metallord
Попробовал не получилось, в Task action функция MyExternalDLL.ReadData(p_KEY) тоже возвращает 0.

А что она должна возвращать?

Цитата: Metallord
Task выполняется повидимому тоже в отдельном потоке.

Естественно, он для этого и предназначен.

5
29 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Metallord
3.В сервере в цикле обновляю параметры оборудования, связь ненадёжная поэтому, чтобы сервер не подвисал нужно ввести отмену считывания параметра по тайм-ауту.

Где выполняется ожидание? В управляемом коде или нативном? Если в последнем, то прервать ожидание можно только если есть соответствующее нативное АПИ.

63K
29 января 2011 года
Metallord
9 / / 09.12.2010
Цитата: hardcase
А что она должна возвращать?



Считывается температура двигателя, она не может быть ноль постоянно. Для проверки объявил MyExternalDLL в потоке где вызывается MyExternalDLL.ReadData(p_KEY). Сразу заработало, ф-ия возвращает значение температуры (39-42).

С похожей проблемой встречался при работе с классом BackgroundWorker, там аналогично в событии DoWork ф-ии глобально объявленных объектов из библиотек не выполняются.

5
29 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Metallord
Считывается температура двигателя, она не может быть ноль постоянно. Для проверки объявил MyExternalDLL в потоке где вызывается MyExternalDLL.ReadData(p_KEY). Сразу заработало, ф-ия возвращает значение температуры (39-42).

С похожей проблемой встречался при работе с классом BackgroundWorker, там аналогично в событии DoWork ф-ии глобально объявленных объектов из библиотек не выполняются.

По-видимому нужно в потоках отличных от основного выполнять инициализацию статических переменных потока (thread static).

63K
29 января 2011 года
Metallord
9 / / 09.12.2010
Цитата: hardcase
Где выполняется ожидание? В управляемом коде или нативном? Если в последнем, то прервать ожидание можно только если есть соответствующее нативное АПИ.



В управляемом.

63K
29 января 2011 года
Metallord
9 / / 09.12.2010
Цитата: hardcase
По-видимому нужно в потоках отличных от основного выполнять инициализацию статических переменных потока (thread static).



Решил делать следующим образом:

 
Код:
Private Sub Worker(ByVal state As Object)
                Dim are As AutoResetEvent = DirectCast(state, AutoResetEvent)

                Static MyExternalDLL as ExternalDLL = New ExternalDLL(Device_Address)
                ...
                ''''''Dim Temperature As Single= MyExternalDLL.ReadData(p_KEY) так работает через раз, периодически возвращает 0.
                Static Temperature As Single= MyExternalDLL.ReadData(p_KEY) 'так всё ок!
                Console.WriteLine("Temperature: " & Temperature.ToString)
                are.[Set]()
        End sub


Я думаю
 
Код:
Static Temperature As Single
работает правильно потому, что она сохраняет предыдущее значение :confused:
5
31 января 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Metallord

Я думаю
 
Код:
Static Temperature As Single
работает правильно потому, что она сохраняет предыдущее значение :confused:


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

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог