ВІКІСТОРІНКА
Навигация:
Інформатика
Історія
Автоматизація
Адміністрування
Антропологія
Архітектура
Біологія
Будівництво
Бухгалтерія
Військова наука
Виробництво
Географія
Геологія
Господарство
Демографія
Екологія
Економіка
Електроніка
Енергетика
Журналістика
Кінематографія
Комп'ютеризація
Креслення
Кулінарія
Культура
Культура
Лінгвістика
Література
Лексикологія
Логіка
Маркетинг
Математика
Медицина
Менеджмент
Металургія
Метрологія
Мистецтво
Музика
Наукознавство
Освіта
Охорона Праці
Підприємництво
Педагогіка
Поліграфія
Право
Приладобудування
Програмування
Психологія
Радіозв'язок
Релігія
Риторика
Соціологія
Спорт
Стандартизація
Статистика
Технології
Торгівля
Транспорт
Фізіологія
Фізика
Філософія
Фінанси
Фармакологія


Системне програмування, характерні особливості.

Системне програмування, характерні особливості.

Системне програмування – це вид програмування, який полягає в роботі з системним програмним забезпеченням. Головною відмінністю системного програмування в порівнянні з прикладним є те, що прикладне програмне призначення випускати ПЗ для користувачів, системне призначення випускати програми, які обслуговують апаратну частину ПК і вимагають значної залежності розроблювального ПЗ від апаратної частини ПК.

Характерна особливість системного програмування:

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

- При розробці ПЗ використовується низько рівневі мови програмування або діалекти, які можуть працювати в ресурсно - обмеженому режимі.

- Розроблювальне ПЗ є максимально раціональним та має мінімальну затримку в часі під час виконання.

- Розроблювальні ПЗ мають малі бібліотеки типів періоду виконання або вони взагалі відсутні.

- Дозволяють прямий доступ до пам’яті та керуючої логіки ПК.

Системне програмування суттєво відрізняється від прикладного, що змушує спеціалістів працювати лише в одній галузі.

Асемблер. Варіанти спільного використання асемблера і мов високого рівня.

Асемблер – це система програмування, яка включає, в себе мову асемблера та транслятори цієї мови . Трансляція зазвичай вимагає двох переглядів початкової програми. При першому перегляді здійснюється розподіл пам’яті і присвоєнню значень символьним . При другому перегляді формується робоча програми у вигляді модуля завантаження. В процесі трансляції асемблер проводить повинний синтаксичний контроль програми, забезпечує при цьому повну діагностику помилок та точне місце їх виконання. Асемблер є низькою мовою програмування , що вимагає більш вузької спеціалізації програміста. Програми на мові асемблер є компактні та швидкі у виконанні.

Мова асемблера, як засіб поліпшення продуктивності додатків написаних на мовах високого рівня використовуються досить широко. Розумне поєднання в одному додатку модулів написаних на мові високого рівня і асемблері дозволяють досягнути високої швидкості роботи програми та зменшити розмір виконуваного коду. На практиці застосовують 2 варіанти спільного використання асемблера і мов високого рівня. В першому випадку використовується окремий файл об’єктного модуля в якому розташовується одна або декілька процедур обробки даних. Виклик такої процедури здійснюється програмою що написана на мові високого рівня. В другому випадку у вихідному тексті додатку на мові високого рівня асемблерна процедура оголошується відповідним чином після чого її можна викликати з будь-якої точки основної програми. Файл з вихідним текстом процедури зазвичай має розширення *. Asm і компілюється будь-яким пакетом компіляторів мовою асемблер (MASM, TASM). Переваги окремо компільованих модулів на асемблері – це можливість використання програмного коду в додатках написаних на різних мовах та деякому випадку використання на різних ОС.

Інструментальні засоби розробки програм на мові Асемблер.

Для розробки програм на мові асемблер велика кількість інструментальних засобів, проте самими популярними є MASM 32. Вибір MASM 32, як середовища розробки програм виходять з слідуючих міркувань:

- MASM 32 є найбільш популярним середовищем програмування.

- MASM 32 дозволяє працювати з мультимедійними розширенням.

- Стандарти файлів прийняті в MASM 32 підтримуються великою кількістю компілятор на мові асемблеру.

- Стандарти і положення MASM 32 повністю сумісні і підтримуються в найбільш популярних середовищах розробки програмних продуктів.

Регістри.

Регістр – комірка пам’яті мікропроцесора розміром від 8 до 32 біт призначена для управління роботою процесора. З точки зору програміста всі регістри можна розподілити на дві частини.

Користувацькі регістри.

Користувацькі регістри. До них належать:

- Регістри загального призначення, що зберігають в пам’яті адреси даних

- Сегментні регістри, які зберігають адреси сегментів пам’яті.

Регістри з пів процесора використовуються в типах даних з плаваючою крапкою. Цілочисельні регістри типу mmx – призначені для роботи з мультимедійними даними.

Регістри стану і управління, містять в собі інформацію про стан мікропроцесора виконуваної програми і дозволяють змінювати цей стан, вони поділяються на дві частини:

- Регістри ознак (ФЛАГИ)

- Регістри показників.

Друга частина регістрів призначена для підтримки різних режимів роботи мікропроцесора, сервісних функцій, а також регістри специфічного значення що використовується лише в певному виді мікропроцесорів.

Регістри загального призначення використовуються в програмах для зберігання операндів (команд) логічних і арифметичних операцій, компонентів адрес пам’яті. Всі регістри цієї групи дозволяють звертатися до своїх молодших частин. Перерахуємо регістри , які належать до цієї групи:

- Регістри акумулятори – застосовуються для зберігання проміжних даних. В деяких командах мікропроцесора використання таких регістрів є обов’язковим. До них належать регістри типу:

Eax(32)/ax(16)/ah(8)/aL(8)

- Базові регістри – застосовуються для зберігання базової адреси деякого об’єкта в пам’яті мікропроцесора. До даних належать регістри типу:

Ebx/bx/bh/bL

- Регістр лічильник – застосовується в командах, які виконуються повторювальні дії. Його використання є часто неявним і прихованим в алгоритмі відповідної команди. До них належать:

Ecx/cx/ch/cL

- Регістр даних – за своїм призначенням працює так само як і регістр акумулятор. В деяких командах він використовується з метою збільшення діапазону пам’яті. До них належать:

Edx/dx/dh/dL

- Регістр індекс джерела – використовується в ланцюжкових операціях і містить поточну адресу елемента в ланцюжку джерелі. До них належать:

Esi/si

- Регістр приймач - використовується в ланцюжкових операціях і містить поточну адресу джерела прийняття даних. До них належать:

Edi/di

- Регістр покажчик стека – містить покажчик вершини стека поточному сегменті . До них належать:

Esp/sp

- Регістр покажчик база стеку – призначений для організації довільного доступу до даних всередині стека. До них належать:

Ebp/bp

Сегментні регістри.

У програмній моделі мікропроцесора є 6 сегментних регістри. Це регістри типу: КС, СС, DC, EC, GC ,FC. Існування такого типу регістрів зумовлено специфікою організації і використання пам’яті мікропроцесора. Вона полягає в тому що мікропроцесор апаратно підтримує структуру організації програми у вигляді 3 частин – сегментів. Така організація пам’яті називається – сегментною. Мікропроцесор підтримує наступні типи сегментів:

- Сегмент коду – містить команда для доступу до програми. Для використання цього сегмента служить регістр КС – сегментний регістр коду. Він містить в собі адресу сегмента з машинними командами до якого має доступ мікропроцесор .

- Сегмент даних – містить дані оброблювальні програмою. Для доступу до цього сегмента служить: DC – сегментний регістр даних, який зберігає адресу сегмента даних поточної програми.

- Сегмент стека – цей сегмент є областю пам’яті, що називається стеком. Роботу зі стеком мікропроцесор організовує наступним чином: Останній записаний в цю область елемент вибирається першим для доступу до цього сегмента служить регістр СС – сегментний регістр даних який містить адресу сегмента у стеку.Три останніх регістри є зарезервованими, тип доступу по них ініціалізується перериваннями при записі або читанні даних.

Сегментна модель пам’яті.

Сегментація – це механізм адресації, який забезпечує існування декількох незалежних адресних простора в межах однієї задачі. В основі механізму сегментації лежить поняття сегменту що є незалежним блоком пам’яті і підтримується на апаратному рівні.

Розрізняють 3 основні моделі сегментної організації пам’яті:

- Сегментна модель пам’яті реального режиму

- Захищеного режиму

- Суцільна модель пам’яті захищеного режиму.

Регістри ESP (SP) – покажчик пам’яті, який вказує на вершину стека. Також програмою може бути змінено регістр EIP – покажчик команд. Цей регістр вказує на інструкцію, яка буде виконуватись наступною . Значення цього регістра змін безпосередньо контролером процесора згідно з інструкціями отримання з пам’яті.

- Ознаки нуля 2F (Zero Flag) -1, якщо результат попередньої операції =0.

- Ознаки знаку SF (Sin Flag) -1, якщо результатом попередньої операції від’ємний.

- Ознака переносу CF (Carry Flag) -1, якщо біт був «перенесений» і cmd бітом, більшого порядку.

- Ознака переривання IF-1, якщо переривання процесором дозволенні

- Ознаки на пряму DF – використовуються для обробки рядків.

Специфікація типів даних

При програмуванні на мові асемблера використовуються дані наступних типів:

Безпосередні дані, що представляють собою числові або символьні значення, що є частиною команди.

Безпосередні дані формуються програмістом в процесі написання програми для конкретної команди асемблера.

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

Ці два типи даних є елементарними, або базовими; робота з ними підтримується на рівні системи команд мікропроцесора. Використовуючи дані цих типів, можна формалізувати і запрограмувати практично будь-яке завдання. Але наскільки це буде зручно - ось питання.

Дані складного типу, які були введені в мову асемблера з метою полегшення розробки програм. Складні типи даних будуються на основі базових типів, які є як би цеглинками для їх побудови. Введення складних типів даних дозволяє дещо згладити відмінності між мовами високого рівня і асемблером. У програміста з'являється можливість поєднання переваг мови асемблера і мов високого рівня (в напрямку абстракції даних), що в кінцевому підсумку підвищує ефективність кінцевої програми.

Обробка інформації, в загальному випадку, процес дуже складний. Це побічно підтверджує популярність мов високого рівня. Одне з безперечних достоїнств мов високого рівня - підтримка розвинених структур даних. При їх використанні програміст звільняється від вирішення конкретних проблем, пов'язаних з поданням числових або символьних даних, і отримує можливість оперувати інформацією, структура якої більшою мірою відображає особливості предметної області розв'язуваної задачі. У той же самий час, чим вище рівень такої абстракції даних від конкретного їх подання в комп'ютері, тим більше навантаження лягає на компілятор з метою створення дійсно ефективного коду. Адже нам уже відомо, що в кінцевому підсумку все написане на мові високого рівня в комп'ютері буде представлено на рівні машинних команд, що працюють тільки з базовими типами даних. Таким чином, найефективніша програма - програма, написана в машинних кодах, але писати сьогодні велику програму в машинних кодах - заняття не має занадто великого сенсу.

Використання АРІ-функцій.

Отже, почнемо з декількох загальних положень про програмування в Windows.

Програмування в Windows грунтується на використанні функцій API (Application Program Interface, тобто інтерфейс програмного продукту). їх кількість сягає двох тисяч. Ваша програма в значній мірі буде складатися з таких викликів. Вся взаємодія з зовнішніми пристроями та ресурсами операційної системи буде відбуватися за допомогою таких функцій.

Список функцій АРІ і їх опис найкраще брати з файлу WIN32.HLP, який поставляється, наприклад, з пакетом Borland C + +.

Головним елементом програми в середовищі Windows є вікно. Для кожного вікна визначається своя процедура обробки повідомлень .

Вікно може містити елементи управління: кнопки, списки, вікна редагування та ін Ці елементи, по суті, також є вікнами, але володіють особливими властивостями. Події, що відбуваються з цими елементами (і самим вікном), призводять до приходу повідомлень в процедуру вікна.

Операційна система Windows використовує лінійну модель пам'яті. Іншими словами, всю пам'ять можна розглядати як один сегмент. Для програміста мовою асемблер це означає, що адреса будь- якої комірки пам'яті буде визначатися вмістом одного 32-бітного регістра, наприклад ЕВХ. Операційна система Windows є багатозадачному середовищем. Кожна задача має свій адресний простір і свою чергу повідомлень. Більш того, навіть в рамках однієї програми може бути здійснена багатозадачність - будь-яка процедура може бути запущена як самостійна задача.

PUSH OFFSET STR2

PUSH HW

CALL MessageBoxA @ 16

Результат виконання будь-якої функції - це, як правило, ціле число, яке повертається в регістр! ЕАХ.

Аналогічним чином в Асемблері легко відтворити ті чи інші Сі-структури. Розглянемо, наприклад, структуру, яка визначає системне повідомлення:

typedef struct tagMSG (/ / MSG HWND hwnd;

UINT message;

WPARAM wParam;

LPARAM IParam;

DWORD time;

POINT pt;

) MSG;

На Асемблері ця структура буде мати вигляд:

MSGSTRUCT STRUC MSHWND DD?

MSMESSAGE DD?

MS WPARAM DD?

MSLPARAM DD?

MSTIME DD?

MSPT DD?

MSGSTRUCT ENDS

Тепер звернемося до структури всієї програми. Як я вже казав, в цьому розділі ми будемо розглядати класичну структуру програми під Windows. У такій програмі є головне вікно, а отже, і процедура головного вікна. В цілому, в коді програми можна виділити наступні секції.

Реєстрація класу вікон Створення головного вікна Цикл обробки черги повідомлень Процедура головного вікна

Звичайно, в програмі можуть бути й інші розділи, але дані розділи утворюють основний кістяк програми. Разберем ці розділи по порядку.

Реєстрація класу вікон.Реєстрація класу вікон здійснюється заї лошогою функції RegisterClassA, єдиним параметром якої є покажчик на структуру WNDCLASS, що містить

Стаорення вікна. На основі зареєстрованого класу за допомогою функції CreateWmdowExA (або CreateWindowA) можна створити екземпляр вікна.

Функція GetMessage () "відловлює" чергове повідомлення з ряду повідомлень програми та

TranslateMessage, то її компетенція стосується повідомлень WM KEYDOWN і WMJCEYUP, які транслюються в WMJTHAR і WMDE^CHAR, *а також WM~SYSKEYDOWN і WMJSYSKEYUP, перетворюються у WM_bYbLHAK і WM_SYSDEADCHAR Сенс трансляції полягає не в заміні, а в відправці додаткових повідомлень. Так наприклад, при натисненні і відпускання алфавітно-цифрової клавші у вікно спочатку прииде повідомлення WMJCEYDOWN, потім WMJCEYUP, а потім вже WM_CHAR.

Процедура головного вікна.

Ось прототип функціі вікна на мові С:

LRESULT CALLBACK WindowFunc (HWND hwnd, UINT message. WPARAM wParam, LPARAM IParam)

Звернемо увагу на представлені параметри. Ось зміст цих параметрів: hwnd - ідентифікатор вікна, Message - ідентифікатор повідомлення, wParam і IParam - параметри, уточнюючі зміст повідомлення (для кожного повідомлення можуть грати різні ролі чи не грати ніяку). Всі чотири параметри, як ви, напевно, вже здогадалися, мають тип DWORD.

А тепер розглянемо "скелет" цієї функції на мові асемблер.

WNDPROC PROC PUSH EBP

PUSH EBP

MOV EBP, ESP

MOV ESP, EBP

POP EBP

RET M

Тут M - об'єм, взятий у стека для передачі параметрів.

Хотілося б зупинитися ще на одному питанні, пов'язаних зі структурою процедури та п виклику.

Існують два основні підходи. Умовно перший підхід можна назвати Сі-підходом, а другий - Паскаль-підходом.

Перший підхід передбачає, що процедура "не знає", скільки параметрів знаходиться в стеку. Природно, у цьому випадку звільнення стека від параметрів має відбуватися після команди виклику процедури, наприклад, за допомогою команди POP або команди ADD ESP, N (N - кількість байт в параметрах).

Другий підхід заснований на тому, що кількість параметрів фіксовано, а стек можна звільнити у самій процедурі. Це досягається виконанням команди RET N (N - кількість байт в параметрах). Як Ви вже, мабуть, здогадалися, виклик функцій АРІ здійснюється по другій схемі.

DIAL1 DIALOG 0, 0, 240, 120

STYLE WS SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX Caption "Приклад діалогового вікна"

FONT 8, "Arial”

{

}

Як бачимо, визначення діалогу починається з рядка, що містить ключове слово DIALOG. В цьому ж рядку далі вказується положення і розмір діалогового вікна. Далі йдуть рядки, що містять інші властивості вікна. Нарешті йдуть фігурні дужки. У даному випадку вони порожні. Це означає, що на вікні немає ніяких керуючих елементів. Тип вікна, а також інших елементів визначається константами, які ми помістили на початку файлу.

MENUP MENU

{

POPUP "& Перший пункт"

{

MENUITEM "& Перший", І MENUITEM "В & якому", 2 POPUP "Підмен & ю"

{

MENUITEM "Десятий пунк & т", 6

}

}

POPUP "& Другий пункт"

{

MENUITEM "Треті & й", З MENUITEM "Четверт & ий", 4 }

MENUITEM "Ви & хід", 5

}

PUSH IDІ APPLICATION

Push 0

CALL LoadlconA @ 8

MOV [WC.CLSHICON], EAX

А ось фрагмент програми для встановлення іконки, зазначеної у файлі ресурсів:

Процеси.

Під процесом будемо розуміти об'єкт, який створюється операційною системою Windows при завантаженні для виконання модуля і отримує в одноосібне користування:

- Віртуальну пам'ять, яка виділяється для нього операційною системою.

- Дескриптори відкриваних ним файлів.

- Список завантажених ним у його власну пам'ять динамічних модулів (DLL).

- Створені ним підпроцеси або потоки, що виконуються незалежно один від одного, у власній пам'яті процесу.

Простіше кажучи кожен виконуваний модуль (. ЕХЕ), запущений в операційній системі Windows, стає процесом.

Кожен процес у відведеному для нього адресному просторі може породжувати ще процеси. Ці процеси виконуються незалежно один від одного і від породжующого їх процесу. Однак породжуючий процес може гіри бажанні "вбити" будь-який з породжених ним процесів. Такі процеси називають ще потоками.

Тепер розглянемо деякі типи багатозадачності. У старій 16-бітної Windows перемикання між завданнями відбувалося лише тоді, коли завдання віддавало управління операційною системою. Така багатозадачність називається невитисняючою. У певному сенсі це було навіть гірше, ніж в операційній системі М8 ООБ. Там елементи багатозадачність здійснювалися за допомогою так званих ТSR-програм. Такі програми називалися ще резидентні. Вони перехоплюють переривання від таймера, клавіатури або іншого пристрою і мали можливість час від часу отримувати управління.

Положення, що існували в старій операційній системі Windows, вимагали від програміста виконання джентльменського правила - не захоплювати надовго час мікропроцесора. Деяким вирішенням проблеми було використання таймерів, а також використання функції РееkMessage замість GetMessage. Функція PeekMessage, на відміну від GetMessage, повертає управління відразу, навіть якщо в черзі немає жодного повідомлення.

У 32-бітних операційних системах Windows (Windows 9х, Windows NТ, Windows 2000) реалізована витісняюча схема багатозадачності, в якій перемиканням між процесами і потоками займається операційна система. Якщо процес занадто довго виконує деяку операцію, то курсор над вікном процесу перетворюється в пісочний годинник. При цьому інші процеси, як і раніше виконуватися, і Ви зможете перемикатися на них. А от доступ до вікна даного процесу може виявитися важким. Вирішити цю проблему можна вже згаданим способом, замінивши в циклі очікування GetMessage на РееkMessage. Однак більш правильним рішенням буде розбивка процесу на певну кількість потоків.

Створити процес можна за допомогою функції CreateProcess.

Параметри:

1-й параметр - вказує на ім'я завантажуваної програми. Ім'я може містити повний шлях до програми.

2- й параметр - його значення залежить від того, чи є перший параметр NULL (0) чи ні. Якщо перший параметр вказує на рядок, то цей параметр трактується як командний рядок запуску (без імені програми). Якщо перший параметр дорівнює NULL, то цей параметр розглядається як командний рядок, перший елемент якого являє собою ім'я програми. Якщо шлях до програми не зазначено, то функція CreateProcess здійснює пошук програми за певним алгоритмом:

Пошук в каталозі, звідки була запущена програма.

Пошук в поточному каталозі.

Пошук в системному каталозі (можна отримати через GetSystemDirectory). Зазвичай системним каталогом є С: \ WINDOWS \ SYSTEM.

Пошук в каталозі Windows (можна отримати через GetWindowsDirectory). Зазвичай цим каталогом є С: \ WINDOWS.

Пошук в каталогах, перерахованих в параметрі PATH оточення.

3- й і 4-й параметри. Використовуються для завдання атрибутів доступу породжуваного процесу. Зазвичай вважають рівним 0.

5- й параметр. Якщо цей параметр 0, то породжувані процес не успадковує дескриптор породжуваного процесу, в іншому випадку породжувані процес успадковує дескриптори.

6- й параметр. Може змінювати властивості породжуваного процесу. Якщо параметр дорівнює нулю, то властивості задаються за замовченням.

7- й параметр. Є вказівником на буфер, який містить параметри середовища. Якщо параметр дорівнює 0, то породжуваний процес успадковує параметри середовища породжуваного процесу.

8- й параметр. Задає поточний каталог для породжуваного процесу. Якщо параметр дорівнює NULL, то породжуваний процес успадковує поточний пристрій і каталог породжуваного процесу.

9- й параметр. Представляє покажчик на структуру, яка містить інформацію про вікно створюваного процесу.

10- й параметр. Вказує на структуру, заповнюється при виконанні запуск програми.

Ось ця структура:

PROCINF STRUC

liProcess DD? ; Дескриптор створеного процесу.

hThread DD? ; Дескриптор головного потоку нового процесу.

Idproc DD? ; Ідентифікатор створеного процесу.

idTlir DD? ; Ідентифікатор головного потоку нового процесу.

PROCINF ENDS

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

Розглянемо тепер структуру, на яку вказує 9-й параметр функції CreateProcess. Ось ця структура:

STARTUP STRUC

cb DD 0

IpReserved DD 0

lpDesktop DD 0

lpTitle DD 0

dwX DD 0

dwY DD 0

dwXSize DD 0

dwYSize DD 0

dwXCountChars DD 0

dwYCountChars DD 0

dwFiUAttribute DD 0

dwFlags DD 0

wShowWindow DW 0

cbReserved2 DW 0

lpReserved2 DD 0

hStdlnput DD 0

hStdOutput DD 0

hStdError DD 0

STARTUP ENDS

Отже, роберемо сенс полыв цыэъ структури

СB – розмір даної структури в байтах. Заповнюється обов’язково.

IpReserved –резерв, повинне дорівнювати 0

IpDesktop – імя робочого столу.

IpTitle – назва вікна для консольних додатків, що створюють своє вікно. Для інших повинно дорівнювати 0.

dwX - координата X лівого верхнього кута вікна.

dwY - координата Y лівого верхнього кута вікна.

dwXSize - розмір вікна з X.

dwYSize - розмір вікна з Y.

dwXCountChars - розмір буфера консолі по X.

dwYCountChars - розмір буфера консолі по Y.

dwFillUAttribute – початковий колір тексту. Має значення тільки для консольних додатків.

dwFlags –прапор значення полів.

 

Ось значення цього прапора.

STARTF USESHOWWINDOW lh // Дозволити поле dwShowWindow

STARTF USESIZE 2h //Дозволити dwXSize та dwYSize.

STARTFJJSEPOSITION 4h //Дозволити dwX та dwX

STARTF_USECOUNTCHARS 8h // Дозволити dwXCountChars та dwYCountChars

STARTF_USEFILLATTR1BUTE lOh // Дозволити dwFillUAttribute

STARTF_FORCEONFEEDBACK 40h // Включити повернення курсору

STARTF FORCEOFFFEEDBACK 80h // Вимкнути повернення курсору

STARTFJJSESTDHANDLES lOOh // Дозволити hStdInput

dwShowWindow –визначає спосіб відображення вікна

cbReserved2 –резерв, повинно бути рівно 0

hStdInput –дескриптор введення (для консолі)

hStdOutput –дескриптор виводу (для консолі)

hStdError -дескриптор виводу повідомлення про помилку (для консолі)

 

Потоки, взаємодія потоків.

Потік може бути створений за допомогою функцій CreateThread. Розглянемо параметри цієї функції.

1- Й параметр. Покажчик на структуру атрибутів доступу. Має значення тільки для Windows NT. Зазвичай покладається NULL.

2- Й параметр. Розмір стека потоку. Якщо параметр дорівнює нулю, то береться розмір стека за замовчуванням, що дорівнює розміру стека батьківського потоку.

3- Й параметр. Покажчик на потокових функцію, з виклику якої починається виконання потоку.

4- й параметр. Параметр для потокової функції.

5- й параметр. Прапор, який визначає стан потоку. Якщо прапор дорівнює 0, то виконання потоку починається негайно. Якщо значення прапора потоку CREATESUSPENDED — (4Н), то потік знаходиться в стан очікування і запускається при виконання функції ResumeThread. .

6- й параметр. Покажчик на змінну, куди буде поміщений дескриптор потоку.

Як вже було сказано, виконання потоку починається з потокової функції. Закінчення роботи цієї функції призводить до природного закінчення роботи потоку. Потік також може закінчити свою роботу, виконавши функцію ExitThread із зазначенням коду виходу.

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

Часто трапляється, що дані неможливо отримувати періодично. Вони можуть, наприклад, залежатиме від діяльності третього процесу. Як же другий процес дізнається, що дані вже готові для передачі? На перший погляд проблема вирішується введенням додаткової змінної, назвемо її Flag. Приймемо, що при Flag = 0 дані не готові, а при Flag — 1 дані готові. Далі діє дуже проста схема.

 

NO_DAT:

CMP FLAG, 1 JNE NO_DAT ... ; передача даних

MOV FLAG, 0

 

Це фрагмент, як Ви розумієте, для другого потоку. Перший же потік також повинен перевіряти змінну Flag і, якщо Flag = 0, помістити нові дані та встановити значення змінної Flag, рівне одиниці. Дана схема є зручною, наприклад, коли один процес чекає закінчення роботи іншого процесу.

А що буде, якщо процес передачі даних повинен здійснюватися багаторазово. Легко передбачити, що дана схема буде працювати і в більш складному випадку. Важливо, щоб другий процес міняв вміст Flag тільки після того, як він візьме дані, а перший процес - після того, як звільнить дані. Якщо порушити це правило, то може виникнути колізія, коли, наприклад, другий процес ще не взяв дані, а вони вже змінилися.

Такий підхід можна здійснити і в більш загальному випадку, коли два потоку (або - два процеси) повинні почергово одержувати доступ до одного ресурсу. Даний підхід припускає, що ресурс відкритий або для одного, або для іншого процесу. Якщо б поставити задачу трохи іншим чином - процес або відкрито, або закритий для доступу, то виникло б деяке ускладнення. Дійсно, імовірна така ситуація, коли обидва потоку очікують відкриття ресурсу. Іншими словами, вони безперервно здійснюють перевірку змінної Flag (CMP FLAG, 1). Може статися, що вони обидва майже одночасно звернуться до ресурсу. Цілком зрозуміло, що тут виникає необхідність в "третій силі", яка б займалася розподілом доступу до ресурсу. Наприклад, посилала б повідомлення спочатку одному потоку і, якщо він очікує доступу, давала доступ саме йому, а потім подібний процес повторюється з другим потоком.

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

 

 

22. Семафори блять! Події нахуй!

Семафор являє собою глобальний об'єкт, що дозволяє синхронізувати роботу двох або декількох процесів або потоків. Для програміста семафор - це просто лічильник. Якщо лічильник дорівнює N, це означає, що до ресурсу мають доступ N процесів. Розглянемо функції для роботи з семафорами.

CreateSemaphore - створює глобальний об'єкт-семафор. Повертає дескриптор семафор.

Параметри функції:

1- й параметр. Покажчик на структуру, яка визначає атрибути доступу. Може мати значення для Windows NT. Зазвичай цей параметр вважається рівним NULL.

2- й параметр. Початкове значення лічильника семафор. Визначає, скільки завдань мають доступ до ресурсу спочатку.

3- й параметр. Кількість завдань, які мають одночасний доступ до ресурсу.

4- й параметр. Покажчик на рядок, що містить ім'я семафор.

OpenSemaphore - відкрити вже створений семафор. Повертає дескриптор семафор. Цю функцію використовують не так часто. Зазвичай створюють семафор і присвоюють його дескриптор глобальної змінної, а потім використовують цей дескриптор в породжуванні потоків.

Параметри функції:

1- й параметр. Визначає бажаний рівень доступу до семафору. Можливі значення: SEMAPHORE_MODIFY_STATE =2Н, дозволити використовувати функцію ReleaseSemaphore,

Synchronize = 100000Н, дозволити використання будь-якої функції очікування, тільки для Windows NT,

SEMAPHORE_ALL_ACCESS = OFOOOOh + Synchronize + ЗН, специфікує всі можливі прапори доступу до семафору.

2- й параметр. Вказує, чи можо наслідувати дескриптор семафору, створюваний функцією CreateProcess; 0 - не може.

3- й параметр. Покажчик на ASCII Z-рядок, що містить ім'я семафор.

WaitForSingleObject - очікувати відкриття семафору. При успішному завершенні, тобто відкриття доступу до об'єкта, функція повертає 0.

Параметри функції:

1- й параметр. Дескриптор семафор.

2- й параметр. Час очікування в мілісекунд.

Якщо параметр дорівнює Infinite = OFFFFFFFFh, то час очікування не обмежено.

ReleaseSemaphore - звільнити семафор і дозволити отримати доступ до ресурсу іншим процесам.

Параметри функції:

1- й параметр. Дескриптор семафор.

2- й параметр. Визначає, яке значення має бути додано до лічильника семафрору. Найчастіше цей параметр дорівнює одиниці.

3- й параметр. Покажчик на змінну, куди має бути поміщено попереднє значення лічильника.

Розглянемо алгоритм роботи з семафором.

Спочатку за допомогою функції CreateSemaphore створюється семафор і його дескриптор присвоюється глобальній змінній. Перед спробою звернення до ресурсів, доступ до яких необхідно обмежити, потік повинен викликати функцію WaitForSingleObject. При відкритті доступу функція повертає 0. По закінченні роботи з ресурсом слід викликати функцію ReleaseSemaphore. Тим самим збільшується лічильник доступу на 1.

3а допомогою Семафору можна регулювати кількість потоків, які одночасно можуть мати доступ до ресурсу.

Максимальне значення лічильника як раз і визначає скільки потоків можуть отримати доступ до ресурсу одночасно.

Події. Подія об'єктом, дуже схожим на семафор, але в видозміненому вигляді.

Розглянемо функції для роботи з подіями.

CreateEvent - створює об’єкт -подія параметри функції.

1-й параметр Має той же зміст, що й перший параметр функції CreateSemaphore. Зазвичай покладається рівним NULL.

2-й параметр якщо параметр не дорівнює нулю то, то подія може бути скинута за допомогою функції ResetEvent. Інакше подія скидається при доступі до нього будь-якого процесу.

3-й параметр якщо параметр дорівнює 0, то подія ініціалізується як скинута в іншому випадку відразу ж подається сигнал про настання відповідної ситуації

4-й параметр. Покажчик на рядок, що містить ім'я події.

Очікування події здійснюється, як і у випадку з семафору, функцією WaitForSingleObject.

Функція OpenEvent аналогічна функції OpenSemaphore.

SetEvent - подати сигнал про настання події.

Параметри функції.

1-й параметр. Дескриптор події.

 

 

Критичні секції.

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

Розглянемо функції для роботи з критичною секцією.

InitializeCriticalSection - дана функція створює об'єкт під назвою критична секція

Параметри функції

1-й параметр. Покажчик на структуру. Поля даної структури викорисговуються

тільки внутрішніми процедурами сенс довільний.

CRITICAL_SECTION STRUCT

DebugInfo DWORD?

LockCount LONG?

RecursionCount LONG?

OwningThread HANDLE?

LockSemaphore HANDLE?

SpinCount DWORD?

CRITICAL_SECTION ENDS

 

EnterCriticalSection – увійти в критичну секцію. Після виконання цієї функції даний потік стає власником даної секції. Наступний потік, виклавши цю функцію, буде перебувати в стані очікування . Параметр функції такий же, що і в попередній функції.

 

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

DeleteCriticalSection –видалити об’єкт «критична секція». Параметр аналогічний попереднім.

 

 

 

Системне програмування, характерні особливості.

Системне програмування – це вид програмування, який полягає в роботі з системним програмним забезпеченням. Головною відмінністю системного програмування в порівнянні з прикладним є те, що прикладне програмне призначення випускати ПЗ для користувачів, системне призначення випускати програми, які обслуговують апаратну частину ПК і вимагають значної залежності розроблювального ПЗ від апаратної частини ПК.

Характерна особливість системного програмування:

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

- При розробці ПЗ використовується низько рівневі мови програмування або діалекти, які можуть працювати в ресурсно - обмеженому режимі.

- Розроблювальне ПЗ є максимально раціональним та має мінімальну затримку в часі під час виконання.

- Розроблювальні ПЗ мають малі бібліотеки типів періоду виконання або вони взагалі відсутні.

- Дозволяють прямий доступ до пам’яті та керуючої логіки ПК.

Системне програмування суттєво відрізняється від прикладного, що змушує спеціалістів працювати лише в одній галузі.

© 2013 wikipage.com.ua - Дякуємо за посилання на wikipage.com.ua | Контакти