:: Меню ::

Головна
  • Про сайт
  • Введення
  • Середовище програмування VB .NET: Visual Studio .NET
  • Вирази, оператори і передача управління
  • Класи і об'єкти
  •  Спадкоємство і інтерфейси
  • Обробка подій і делегати
  • Обробка помилок в VB .NET
  • Форми Windows, графічний вивід і друк
  • Уведення-виведення
  •  Багатопотокові застосування
  • Підтримка баз-даних в VB .NET
  • Короткий огляд ASP .NET
  • Складки .NET, установка додатків і COM Interop
  • Книга для гостей
    Контакти
    Добавити у вибране

    :: Друзі ::

     
     

    :: Лічильники ::

    = =

     

     

     

     

    Спільна робота з даними у міру їх створення

    У багатопотокових застосуваннях часто зустрічається ситуація, коли потоки не тільки працюють із загальними даними, але і чекають їх появи (тобто потік 1 повинен створити дані, перш ніж потік 2 зможе їх використовувати). Оскільки дані є загальними, доступ до них необхідно синхронізувати. Також необхідно передбачити засоби для сповіщення чекаючих потоків про появу готових даних.

    Подібна ситуація зазвичай називається проблемою «постачальник/споживач». Потік намагається звернутися до даних, яких ще немає, тому він повинен передати управління іншому потоку, що створює потрібні дані. Проблема вирішується кодом наступного вигляду:

    • Потік 1 (споживач) активізується, входите синхронізований метод, шукає дані, не знаходить їх і переходить в стан очікування. Предварітел'но він повинен зняти блокування, щоб не заважати роботі потока- постачальника.
    • Потік 2 (постачальник) входить в синхронізований метод, звільнений потоком 1, створює дані для потоку 1 і якимсь чином оповіщає потік 1 про наявність даних. Потім він знімає блокування, щоб потік 1 зміг обробити нові дані.

    Не намагайтеся вирішити цю проблему постійною активізацією потоку 1 з перевіркою стану умовної змінної, значення которой>устанавліваєтся потоком 2. Таке рішення серйозно вплине на швидкодію вашої програми, оскільки в більшості випадків потік 1 активізуватиметься без всяких причин; а потік 2 переходитиме в очікування так часто, що у нього не залишиться часу на створення даних.

    Зв'язки «постачальник/споживач» зустрічаються дуже часто, тому в бібліотеках класів багатопотокового програмування для таких ситуацій створюються спеціальні примітиви. У .NET ці примітиви називаються Wait і Pulse-pulseal 1 і є частиною класу Monitor. Малюнок 10.8 пояснює ситуацію, яку ми збираємося запрограмувати. У програмі організовуються три черги потоків: черга очікування, черга блокування і черга виконання. Планувальник потоків не виділяє процесорний час потокам, що знаходяться в черзі очікування. Щоб потоку виділявся час, він повинен переміститися в чергу виконання. В результаті робота додатку організовується набагато ефективніше, ніж при звичайному опиті умовної змінної.

    На псевдокоді ідіома споживача даних формулюється так:

    ' Вхід в синхронізований блок наступного вигляду

    While немає даних

    Перейти в чергу очікування

    Loop

    Якщо дані є, обробити їх.

    Покинути синхронізований блок

    Відразу ж після виконання команди Wait потік припиняється, блокування знімається, і потік переходить в чергу очікування. При знятті блокування потік, що знаходиться в черзі виконання, дістає можливість працювати. З часом один або декілька заблокованих потоків створять дані, необхідні для роботи потоку, що знаходиться в черзі очікування. Оскільки перевірка даних здійснюється в циклі, перехід до використання даних (після циклу) відбувається лише за наявності даних, готових до обробки.

    На псевдокоді ідіома постачальника даних виглядає так:

    ' Вхід в синхронізований блок вигляду

    While дані НЕ потрібні

    Перейти в чергу очікування

    Else Провести дані

    Після появи готових даних викликати Pulse-pulseall.

    щоб перемістити один або декілька потоків з черги блокування в чергу виконання. Покинути синхронізований блок (і повернутися в чергу виконання)

    Припустимо, наша програма моделює сім'ю з одним батьком, який заробляє гроші, і дитиною, яка ці гроші витрачає. Коли гроші кінчаються, дитині доводиться чекати приходу нової суми. Програмна реалізація цієї моделі виглядає так:

    1 Option Strict On

    2 Imports System.Threading

    3 Module Modulel

    4 Sub Main()

    5 Dim thefamily As New Family()

    6 thefamily.StartltsLife()

    7 End Sub

    8 End fjodule

    9

    10 Public Class Family

    11 Private mmoney As Integer

    12 Private mweek As Integer = 1

    13 Public Sub Startltslife()

    14 Dim athreadstart As New Threadstaruaddressof Me.Produce)

    15 Dim bthreadstart As New Threadstaruaddressof Me.Consume)

    16 Dim athread As New Thread(athreadstart)

    17 Dim bthread As New Thread(bthreadstart)

    18 athread.Name = "Produce"

    19 athread.Start()

    20 bthread.Name = "Consume"

    21 bthread. Start()

    22 End Sub

    23 Public Property Theweek() As Integer

    24 Get

    25 Return mweek

    26 End Get

    27 Set(Byval Value As Integer)

    28 mweek - Value

    29 End Set

    30 End Property

    31 Public Property Ourmoney() As Integer

    32 Get

    33 Return mmoney

    34 End Get

    35 Set(Byval Value As Integer)

    36 mmoney =Value

    37 End Set

    38 End Property

    39 Public Sub Produce()

    40 Thread.Sleep(500)

    41 Do

    42 Monitor.Enter(Me)

    43 Do While Me.OurMoney > 0

    44 Monitor.Wait(Me)

    45 Loop

    46 Me.OurMoney =1000

    47 Monitor.PulseAll(Me)

    48 Monitor.Exit(Me)

    49 Loop

    50 End Sub

    51 Public Sub Consume()

    52 Msgbox("Am in consume thread")

    53 Do

    54 Monitor.Enter(Me)

    55 Do While Me.OurMoney = 0

    56 Monitor.Wait(Me)

    57 Loop

    58 Console.WriteLine("Dear parent I just spent all your " & _

    money in week " & Theweek)

    59 Theweek += 1

    60 If Theweek = 21 *52 Then System.Environment.Exit(0)

    61 Me.OurMoney =0

    62 Monitor.PulseAll(Me)

    63 Monitor.Exit(Me)

    64 Loop

    65 End Sub

    66 End Class

    Метод Startltslife (рядки 13-22) здійснює підготовку до запуску потоків Produce і Consume. Найголовніше відбувається в потоках Produce (рядки 39-50) і Consume (рядки 51-65). Процедура Sub Produce перевіряє наявність грошей, і якщо гроші є, переходить в чергу очікування. Інакше батько генерує гроші (рядок 46) і оповіщає об'єкти в черзі очікування про зміну ситуації. Врахуйте, що виклик Pulse-pulse All набуває чинності лише при знятті блокування командою Monitor.Exit. І навпаки, процедура Sub Consume перевіряє наявність грошей, і якщо грошей немає — оповіщає про це чекаючого батька. Рядок 60 просто завершує програму після 21 умовного року; виклик System. Environment.Exit(0) є .NET-аналогом команди End (команда End теж підтримується, але на відміну від System. Environment. Exit вона не дозволяє повернути код завершення операційній системі).

    Потоки, переведені в чергу очікування, мають бути звільнені іншими час-тямі вашої програми. Саме з цієї причини ми вважаємо за краще використовувати Pulseall замість Pulse. Оскільки заздалегідь невідомо, який саме потік буде активізований при виклику Pulse 1 при відносно невеликій кількості потоків в черзі з таким же успіхом можна викликати Pulseall.

     




    :: Наша кнопка ::

    Отримати код:

    Підтримайте наш сайт і розмістіть нашу кнопку на своєму ресурсі.


    :: Реклама ::

    Скачати безкоштовно програму Microsoft Front Page 2003


    :: Посилання ::

    -


     

     

     


    Copyright ©