|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||
|
Наступний
крок: кнопка Show Count
Допустимо, ви
вирішили проявити творчу
фантазію і надати формі вигляду,
показаному на мал. 10.9. Звернете
увагу: кнопка Show Count поки
недоступна.
Мал. 10.10. Форма із
заблокованою кнопкою Передбачається,
що окремий потік виконує
підрахунок і розблоковує недоступну
кнопку. Звичайно, це можна зробити;
більш того, таке завдання виникає
достатньо часто. На жаль, ви не
зможете діяти найбільш
очевидним чином — організувати
зв'язок вторинного потоку з потоком
графічного інтерфейсу, зберігаючи
посилання на кнопку Showcount в
конструкторі, або навіть з
використанням стандартного
делегата. Інакше кажучи, ніколи не
використовуйте варіант, приведений
нижче (основні помилкові рядки
виділені жирним шрифтом). Public
Class Randomcharacters Private m_0ata As Stringbuilder Private m_countdone As Boolean Private mjength. m_count As Integer Private m_button As
Windows.Forms.Button Public Sub New(Byva1 n As Integer,_ Byval b As Windows.Forms.Button) m_length
= n - 1 m_data = New Stringbuilder(mjength) m_button = b Makestring() End
Sub Private Sub Makestring() Dim I As Integer Dim myrnd As New Random() For I =
0 To m_length m_data.Append(Chr(myrnd.Next(65. 90))) Next End Sub Public Sub
Startcount() Getees() End
Sub Private Sub Getees() Dim I As Integer For I =
0 To mjength If
m_data.Chars(I) =
Cchar("E") Then m_count += 1 End If
Next m_countdone =True m_button.Enabled=True End
Sub Public Readonly Property Getcount()As Integer Get If Not (m_countdone)
Then Throw New Exception("Count
not yet done") Else Return m_count End If End Get End
Property Public Readonly Property Isdone() As Boolean Get Return m_countdone End Get End Property End
Class
Цілком імовірно, що в деяких
випадках цей код працюватиме. Проте:
Якщо
ви порушите ці правила, ми
гарантуємо, що у ваших
багатопотокових графічних програмах
виникатимуть тонкі, невловимі
помилки. Та все ж здоровий
глузд підказує, що в
графічних застосуваннях повинні
існувати засоби модифікації
елементів з іншого потоку. У .NET
Framework існує потоково-безпечний
спосіб виклику методів додатків GUI
з іншого потоку. Для цієї мети
використовується особливий тип делегатів
Method Invoker з простору імен System.Windows.
Forms. У наступному фрагменті приведений
новий варіант методу Getees (змінені
рядки виділені жирним шрифтом): Private Sub Getees() Dim I As Integer For I =
0 To m_length If
m_data.Chars(I) = Cchar("E")
Then m_count += 1 End If
Next m_countdone = True Try Dim mylnvoker As New Methodlnvoker(Addressof Updatebutton) myinvoker.Invoke()
Catch e As Threadlnterruptedexception 'Невдача End Try End Sub Public Sub
Updatebutton() m_button.Enabled =True End Sub Міжпоточні
звернення до кнопки здійснюються
не безпосередньо, а через Method Invoker. .NET
Framework гарантує, що цей варіант
безпечний по відношенню до потоків. Чому
при багатопотоковому
програмуванні виникає
стільки проблем? Тепер, коли ви
отримали деяке уявлення про
багатопотокове програмування і про
потенційні проблеми, з ним
зв'язаних, ми вирішили, що в кінці
цього розділу буде доречно відповісти
на питання, винесене в заголовок
підрозділу. Одна з
причин полягає в тому,
що многопотрчность —
процес нелінійний, а ми звикли
до лінійної моделі
програмування. На перших порах важко звикнути
до самої думки про те, що
виконання програми може
уриватися випадковим чином, а
управління передаватиметься іншому коду.
Проте існує і інша, фундаментальніша
причина: в наші
дні програмісти дуже рідко
програмують на асемблері
або хоч
би проглядають дизасембльовані результати роботи
компілятора. Інакше їм було б набагато
простіше звикнути до думки, що
одній команді мови високого рівня можуть
відповідати десятки
асемблерних інструкцій. Потік
може уриватися після будь-якої з
цих інструкцій, а отже —
і посеред команди високого рівня. Але і це не все:
сучасні компілятори
оптимізують швидкодію
програм, а устаткування
комп'ютера може втручатися в
процес управління пам'яттю. Як
наслідок, компілятор або
устаткування може без вашого
відома змінити порядок команд,
вказаний в початковому тексті
програми [ Багато компіляторів
оптимізують циклічні операції
копіювання масивів виду for i=0 to n:b(i)=a(i):ncxt.
Компілятор (або навіть
спеціалізований пристрій
управління пам'яттю) може просто
створити масив, а потім заповнити
його однією операцією копіювання
замість багатократного копіювання
окремих елементів! ]. Сподіваємося, ці пояснення допоможуть вам краще зрозуміти, чому багатопотокове програмування породжує стільки проблем, — або принаймні менше дивуватися побачивши дивної поведінки ваших багатопотокових програм!
Нужен сервер: VPS. |
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||