Так ось головна фіча в потоках в тому, що вони можуть виконуватися майже паралельно (або по науковому псевдопараллельно) саме майже, а не зовсім. Насправді справжня паралельність можлива тільки на багатопроцесорної машині (2 і більше проца). Але WiNdoWs, може імітувати таку роботу (і не вини її в цьому, якщо виниш, то читай вище) тобто вона (Windoz) для кожного потоку виділяє невелику кількість процесорного часу (кілька мілісекунд), по закінченню це часу відоус дає попрацювати іншому потоку потім наступного і так далі. І як ти вже напевно зміг здогадатися, для кожного потоку визначено відповідний пріоритет виконання. Простіше кажучи, при написання коду ми можемо вказувати системі як часто вона повинна виділяти потоку процесорного часу. Як це зробити буде розказано нижче.
Ще хотілося б відзначити те, що корпорація Inprise не рекомендує створювати в програмі більше 16 потоків, якщо прога працює на однопроцессорной машині.
На цьому з теорією мабуть можна закінчити і перейти до самого програмуванні. Багатопотокового програмного продукту (програмний продукт Яке гарне словосполучення).
Крок 2. Створити новий додаток (File-> New Application).
Шаг3. На з'явилися форму кинь одну кнопку (у мене це буде Button1) і дві області малювання (у мене це буде PaintBox1 і PaintBox2 відповідно).
Крок 4. У модулі головної форми опишемо новий метод (у мене це буде gtextout), який в якості параметра буде отримувати полотно і виводити на ньому, в довільному місці, будь-який символ (у мене це буде "@" без лапок відповідно).
Крок 4.1. Розглянемо детальніше як виконати на практиці вище вказане дію.
Створив нову процедуру. Впиши procedure gtextout (CNV. TCanvas) перед словом private. Потім дави по написаному правою кнопкою миші і в що з'явилася менюшки вибирай "Comlete class at cursor" (по-моєму так пишеться (Просто в Delphi3 етого ще немає)).
Якщо ти все зробив правильно, то ти повинен побачити наступне:
Їдемо далі. Між begin і end напиши код з лістінга1.
Думаю в більш докладних пояснень лістінг1 не потребує, скажу лише тільки те, що метод TextOut в загальному вигляді мала б такий вигляд TextOut (коордіната_по_Х, коордіната_по_Y, виводімий_сімвол_); (Тільки не забудь, що ти використовуєш метод об'єкта TCanvas, а то буде викликана однойменна API фунция TextOut, яка також призначена для виведення тексту, але відрізняється кількістю і типом параметрів).
Тепер дабавіть ще 2 процедури вищевказаним способом тільки в першій
Між begin і end впиши gTextOut (PaintBox1.Canvas), а в другій gTextOut (PaintBox2.Canvas). На практиці це має виглядати приблизно так:
Ці методи отримують в якості параметра Полотно і потім процедура gTextOut виводить на цьому полотні собаку (@). Так а навіщо ми зробили так?
Справа в тому, що коли методи класів одночасно викликаються з декількох потоків, це може привести до небажаних наслідків. Наприклад проблеми можуть вилізти при швидкому чергування обробки процесу виведення зображення на екран, коли системі потрібно обробляти об'єкти інших класів.
Ну а тепер приступимо до того власне через що ми тут зібралися тобто до створення потоку. Клікай File-> New-> Thread Object.
У діалоговому вікні назви класу вкажемо TMyThread. Цей клас буде спадкоємцем класу потоку TThread. Після це виникає файл з порожнім описом цього класу.
Так а тепер повернемося до нашої можливої помилки (пункт1) і ти матимеш навіщо ми створювали 2 «зайві» процедури. Щоб не виникало подібних помилок (читай пункт1) в класі Thread визначено метод гарантовано-безпечного виконання таких методів. Цей метод відповідає за синхронізацію всіх потоків. І як параметр отримує тільки назва методу. Ось саме для цього нам і треба було створювати 2 процедури. Ось опис методу по синхронізації:
Їдемо далі. Але ось ще один проблем як визначити з всередині потоку який метод потрібно викликати в даний момент? Для того, щоб відповісти на це питання введемо змінну типу Boolean з ім'ям W. Потім при створення екземпляра потоку їй присвоєно значення TRUE якщо треба виконувати метод OUTD1, і FALSE якщо OUTD2 відповідно.
Сам процес роботи потоку описується в його методі Execute. Після перевизначення цього методу у нас вийде наступне.
Отже, що це нас тут таке. СвойствоTerminated отримує значення TRUE, коли прога отримує значення про завершення роботи. => Ми будемо працювати до завершення роботи програми. Потім якщо w = true то викликається процедура OUTD1, в іншому випадку OUTD2.
Тепер в розділі implementation напиши наступне: uses unit1; (Підключаємо модуль1);
Тепер перейдемо до першого юниту (unit1) .Подключі Uni2. Потім, Створити обробник подій для Button1 і напиши там лістинг 2.
Чого ми тут накоїли? У рядку ми описуємо дві змінний, це наші майбутні потоки. У рядку ми створюємо новий потік за допомогою методу Create у якого є один параметр, він має значення True якщо потік стартує після виклику методу Resume, і False якщо потік стартує відразу ж після створення. У рядку встановлюємо значення змінної W (ти ж пам'ятаєш цю закарлюку) .В рядку ставимо пріоритет для даного потоку.
Можливі варіанти значень для цього властивості перераховані нижче:
tpTimeCritical - Максимальний пріоритет
tpHighest - Пріоритет на 2 пункти вище норми
tpHigher - Пріоритет на 1 пункт вище норми
tpNormal - Нормальний пріоритет
tpLower - Пріоритет на 1 пункт нижче норми
tpLowest - Пріоритет на 2 пункти нижче норми
tpIdle - Потік виконується, коли твоєї ОС нічого робити
P.S. Ну ніби все. Приклад хоч і простенький, але все ж пізнавальний. Мабуть, дам ще маленька порада. У тебе є мій код невеликий проги, але ти спробую в ньому чогось змінити, може прибрати що-небудь або додати свого і подивися потім, що у тебе вийде, це буде набагато кориснішою якщо ти прочитаєш і скажеш собі усьо ЗРОЗУМІЛО! і забудеш про це. Взагалі вибір за тобою. Мені залишається лише сказати Уд @ Чи в КОДІНГ, в дівчатах (нерозумно висловився ну сенс ти зрозумів), і великий Уд @ Чи на Сесії (якщо ти студент, як я). ... Якщо у тебе виникнуть питання то пиши ([email protected]) спробую відповісти. Бувай.
Written by: Litex [[email protected]]
Вихідні тексти прикладу забирай тут: