74954-1 (Потоки в Visual Basic), страница 3

2016-07-31СтудИзба

Описание файла

Документ из архива "Потоки в Visual Basic", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "74954-1"

Текст 3 страницы из документа "74954-1"

(ByVal lpSecurityAttributes As Long, ByVal _

dwStackSize As Long, ByVal lpStartAddress As Long, _

ByVal lpParameter As Long, ByVal dwCreationFlags _

As Long, lpThreadId As Long) As Long

Declare Function CloseHandle Lib "kernel32" _

(ByVal hObject As Long) As Long

' Start the background thread for this object

' using the invalid free threading approach.

Public Function StartBackgroundThreadFree _

(ByVal qobj As clsBackground)

Dim threadid As Long

Dim hnd&

Dim threadparam As Long

' Free threaded approach

threadparam = ObjPtr(qobj)

hnd = CreateThread(0, 2000, AddressOf _

BackgroundFuncFree, threadparam, 0, threadid)

If hnd = 0 Then

' Return with zero (error)

Exit Function

End If

' We don't need the thread handle

CloseHandle hnd

StartBackgroundThreadFree = threadid

End Function

Функция CreateThread имеет шесть параметров:

lpSecurityAttributes - обычно устанавливается в нуль, чтобы использовать заданные по умолчанию атрибуты защиты.

dwStackSize - размер стека. Каждый поток имеет собственный стек.

lpStartAddress - адрес памяти, где стартует поток. Он должен быть равен адресу функции в стандартном модуле, полученном при использовании оператора AddressOf.

lpParameter - long 32 разрядный параметр, который передается функции, запускающей новый поток.

dwCreationFlags - 32 бит переменная флагов, которая позволяет Вам управлять запуском потока (активный, приостановленный и т.д.). Подробнее об этих флагах можно почитать в Microsoft's online 32 bit reference.

lpThreadId - переменная, в которую загружается уникальный идентификатором нового потока.

Функция возвращает дескриптор потока.

В этом случае мы передаем указатель на объект clsBackground, который мы будем использовать в новом потоке. ObjPtr восстанавливает значение указателя интерфейса в переменную qobj. После создания потока закрывается дескриптор при помощи функции CloseHandle. Это действие не завершает поток, - поток продолжает выполняться до выхода из функции BackgroundFuncFree. Однако, если мы не закрыли дескриптор, то объект потока будет существовать даже после выхода из функции BackgroundFuncFree. Все дескрипторы

потока должны быть закрыты и при завершении потока система освобождает занятые потоком ресурсы.

Функция BackgroundFuncFree имеет следующий код:

' A free threaded callback.

' A free threaded callback.

' This is an invalid approach, though it works

' in this case.

Public Function BackgroundFuncFree(ByVal param As _

IUnknown) As Long

Dim qobj As clsBackground

Dim res&

' Free threaded approach

Set qobj = param

Do While Not qobj.DoTheCount(100000)

Loop

' qobj.ShowAForm ' Crashes!

' Thread ends on return

End Function

Параметром этой функции является- указатель на интерфейс (ByVal param As IUnknown). При этом мы можем избежать неприятностей, потому что под COM каждый интерфейс основывается на IUnknown, так что такой тип параметра допустим независимо от типа интерфейса, передаваемого функции. Мы, однако, должны немедленно определить param как тип объекта, чтобы затем его использовать. В этом случае qobj установливается как объект clsBackground, который был передан к объекту StartBackgroundThreadFree.

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

Доступ к объекту qobj чрезвычайно быстр из-за использования подхода свободного потока (free threading) - никакая переадресация (marshalling) при этом не используется.

Обратите внимание на то, что если Вы попробуете использовать объект clsBackground, который показывает форму, то это приведет к сбоям приложения. Обратите также внимание на то, что событие завершения никогда не происходит в клиентской форме. Действительно, даже Microsoft Systems Journal, который описывает этот подход, содержит очень много предупреждений о том, что при использовании этого подхода есть некоторые вещи, которые не работают.

Некоторые разработчики, кто пробовали развертывать приложения, применяющие этот тип многопоточности, обнаружили, что их приложения вызывают сбои после обновления к VB5 service pack 2.

Является ли это дефектом Visual Basic?

Означает ли это, что Microsoft не обеспечила совместимость?

Ответ на оба вопроса: Нет

Проблема не в Microsoft или Visual Basic.

Проблема состоит в том, что вышеупомянутый код является мусором.

Проблема проста - Visual Basic поддерживает объекты и в модели одиночного потока и в apartment model.

Позвольте мне перефразировать это: объекты Visual Basic являются COM объектами и они,согласно COM соглашению, будут правильно работать как в модели одиночного потока так и в apartment model. Это означает, что каждый объект ожидает, что любые вызовы методов будут происходить в том же самом потоке, который создал объект.

Пример, показанный выше, нарушает это правило.

Это нарушает соглашение COM.

Что это означает?

Это означает, что поведение объекта подчиненно изменениям, так как Visual Basic постоянно модифицируется.

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

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

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

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

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

Этот подход является программной алхимией. Это безответственно и ни один программист не должен когда-либо использовать это. Точка.

Обратно к функции API CreateThread

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

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

Пример MTDEMO3 демонстрирует этот подход в форме frmMTDemo3, имеющей код, который запускает класс фона в apartment model следующим образом:

Private Sub cmdCreateApt_Click()

Set c = New clsBackground

StartBackgroundThreadApt c

End Sub

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

' Structure to hold IDispatch GUID

Type GUID

Data1 As Long

Data2 As Integer

Data3 As Integer

Data4(7) As Byte

End Type

Public IID_IDispatch As GUID

Declare Function CoMarshalInterThreadInterfaceInStream Lib _

"ole32.dll" (riid As GUID, ByVal pUnk As IUnknown, _

ppStm As Long) As Long

Declare Function CoGetInterfaceAndReleaseStream Lib _

"ole32.dll" (ByVal pStm As Long, riid As GUID, _

pUnk As IUnknown) As Long

Declare Function CoInitialize Lib "ole32.dll" (ByVal _

pvReserved As Long) As Long

Declare Sub CoUninitialize Lib "ole32.dll" ()

' Start the background thread for this object

' using the apartment model

' Returns zero on error

Public Function StartBackgroundThreadApt(ByVal qobj _

As clsBackground)

Dim threadid As Long

Dim hnd&, res&

Dim threadparam As Long

Dim tobj As Object

Set tobj = qobj

' Proper marshaled approach

InitializeIID

res = CoMarshalInterThreadInterfaceInStream _

(IID_IDispatch, qobj, threadparam)

If res <> 0 Then

StartBackgroundThreadApt = 0

Exit Function

End If

hnd = CreateThread(0, 2000, AddressOf _

BackgroundFuncApt, threadparam, 0, threadid)

If hnd = 0 Then

' Return with zero (error)

Exit Function

End If

' We don't need the thread handle

CloseHandle hnd

StartBackgroundThreadApt = threadid

End Function

Функция StartBackgroundThreadApt немного более сложна чем ее эквивалент при применении подхода свободных потоков. Первая новая функция называется InitializeIID. Она имеет следующий код:

' Initialize the GUID structure

Private Sub InitializeIID()

Static Initialized As Boolean

If Initialized Then Exit Sub

With IID_IDispatch

.Data1 = &H20400

.Data2 = 0

.Data3 = 0

.Data4(0) = &HC0

.Data4(7) = &H46

End With

Initialized = True

End Sub

Вы видите, нам необходим идентификатор интерфейса - 16 байтовая структура, которая уникально определяет интерфейс. В частности нам необходим идентификатор интерфейса для интерфейса IDispatch (подробная информация относительно IDispatch может быть найдена в моей книге Developing ActiveX Components). Функция InitializeIID просто инициализирует структуру IID_IDISPATCH к корректным значениям для идентификатора интерфейса IDispatch. Значение Это значение получается с помощью использования утилиты просмотра системного реестра.

Почему нам необходим этот идентификатор?

Потому что, чтобы твердо придерживаться соглашения COM о потоках, мы должны создать промежуточный объект (proxy object) для объекта clsBackground. Промежуточный объект должен быть передан новому потоку вместо первоначального объекта. Обращения к новому потоку на промежуточном объекте будут переадресованы (marshaled) в текущий поток.

CoMarshalInterThreadInterfaceInStream выполняет интересную задачу. Она собирает всю информацию, необходимую при создании промежуточного объекта, для определенного интерфейса и загружает ее в объект потока (stream object). В этом примере мы используем интерфейс IDispatch, потому что мы знаем, что каждый класс Visual Basic поддерживает IDispatch и мы знаем, что поддержка переадресации (marshalling) IDispatch встроена в Windows - так что этот код будет работать всегда. Затем мы передаем объект потока (stream object) новому потоку. Этот объект разработан Windows, чтобы быть передаваемым между потоками одинаковым способом, так что мы можем безопасно передавать его функции CreateThread. Остальная часть функции StartBackgroundThreadApt идентична функции StartBackgroundThreadFree.

Функция BackgroundFuncApt также сложнее чем ее эквивалент при использовании модели свободных потоков и показана ниже:

' A correctly marshaled apartment model callback.

' This is the correct approach, though slower.

Public Function BackgroundFuncApt(ByVal param As Long) As Long

Dim qobj As Object

Dim qobj2 As clsBackground

Dim res&

' This new thread is a new apartment, we must

' initialize OLE for this apartment

' (VB doesn't seem to do it)

res = CoInitialize(0)

' Proper apartment modeled approach

res = CoGetInterfaceAndReleaseStream(param, _

IID_IDispatch, qobj)

Set qobj2 = qobj

Do While Not qobj2.DoTheCount(10000)

Loop

qobj2.ShowAForm

' Alternatively, you can put a wait function here,

' then call the qobj function when the wait is satisfied

' All calls to CoInitialize must be balanced

CoUninitialize

End Function

Первый шаг должен инициализировать подсистему OLE для нового потока. Это необходимо для переадресации (marshalling) кода, чтобы работать корректно. CoGetInterfaceAndReleaseStream создает промежуточный объект для объекта clsBackground и реализует объект потока (stream object), используемый для передачи данных из другого потока. Интерфейс IDispatch для нового объекта загружается в переменную qobj.

Теперь возможно получить другие интерфейсы - промежуточный объект будет корректно переадресовывать данные для каждого интерфейса, который может поддерживать.

Теперь Вы можете видеть, почему цикл помещен в эту функцию вместо того, чтобы находиться непосредственно в объекте. Когда Вы впервые вызовите функцию qobj2.DoTheCount, то увидите, что код выполняется в начальном потоке! Каждый раз, когда Вы вызываете метод объекта, Вы фактически вызываете метод промежуточного объекта. Ваш текущий поток приостанавливается, запрос метода переадресовывается первоначальному потоку и вызывается метод первоначального объекта в той же самом потоке, который создал объект. Если бы цикл был в объекте, то Вы бы заморозили первоначальный поток.

Хорошим результатом применения этого подхода является то, что все работает правильно. Объект clsBackground может безопасно показывать формы и генерировать события. Недостатком этого подхода является, конечно, его более медленное исполнение. Переключение потоков и переадресация (marshalling) - относительно медленные операции. Вы фактически никогда не захотите выполнять фоновую операцию как показано здесь.

Но этот подход может чрезвычайно хорошо работать, если Вы можете помещать фоновую операцию непосредственно в функцию BackgroundFuncApt! Например: Вы могли бы иметь фоновый поток, выполняющий фоновые вычисления или операцию ожидания системы. Когда они будут завершены, вы можете вызывать метод объекта, который сгенерирует событие в клиенте. Храня количество вызовов метода, небольшое относительно количества работы, выполняемой в фоновой функции, Вы можете достигать очень эффективных результатов.

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5173
Авторов
на СтудИзбе
436
Средний доход
с одного платного файла
Обучение Подробнее