
- •6.050101 «Комп’ютерні науки»
- •Загальні вимоги до виконання лабораторних робіт
- •Лабораторна робота №1
- •1. Основні теоретичні відомості
- •1.1 Основні поняття
- •1.2 Створення процесу
- •1.3 Створення потоку
- •2. Хід роботи
- •4. Завдання
- •5. Контрольні запитання
- •6.Список використаної літератури
- •Додаток 1
- •Додаток 2
- •Додаток 3
- •Функція CreateProcess створює новий процес.
- •Додаток 4
- •Додаток 5
- •Addr ThreadId – Створює новий потік.
- •Додаток 6
- •Додаток 7
- •Лабораторна робота №2
- •1. Основні теоретичні відомості
- •1.1 Механізми міжпроцесової взаємодії
- •1.2 Механізми синхронізації процесів та потоків
- •1.3 Об’єкти синхронізації
- •1.4 Очікуючі функції
- •1.5 Створення атома
- •1.6 Створення каналу
- •2. Хід роботи
- •4. Завдання
- •5. Контрольні запитання
- •6.Список використаної літератури
- •Додаток 1
- •Додаток 2
- •Додаток 3
- •Додаток 4
- •Додаток 5 Детальний опис функції створення анонімного каналу
- •Додаток 6 Детальний опис функції створення іменованого каналу
- •Додаток 7
- •Додаток 8
- •Додаток 9 Текст програми створення анонімного каналу
- •Додаток 10
- •Лабораторна робота №3
- •1. Основні теоретичні відомості
- •2. Приклад програми створення dll
- •Опис програми My_dll.Asm та файлу лістінга My_dll.Def
- •4. Трансляція та компонування dll Для того, щоб відтранслювати(ml.Exe) та зкомпонувати (link.Exe) даний .Asm код, потрібно використовувати наступні параметри:
- •5. Приклад використання функції з бібліотеки
- •Приклад програми завантаження dll
- •7. Створення файлу лістінгу існуючої бібліотеки
- •8. Приклад передачі даних у функцію бібліотеки Створення динамічно завантажуваної бібліотеки
- •Передача параметру у функцію бібліотеки
- •9. Хід роботи
- •11. Завдання
- •12. Контрольні запитання
- •13. Список використаної літератури
- •Лабораторна робота №4
- •1. Основні теоретичні відомості
- •Параметри функції CreateToolhelp32Snapshot:
- •2. Перегляд процесів
- •3. Перегляд потоків
- •Значення результуючого параметру (регістр еах) таке саме як в Process32First і Process32Next.
- •4. Перегляд хіпів асоційованих з процесом
- •5. Перегляд модулів, які використовує процес
- •6. Керування процесами
- •7. Хід роботи
- •9. Завдання На 75 балів виконати 4 завдання:
- •10. Контрольні запитання
- •11. Список використаної літератури
- •Додаток 1
- •Лабораторна робота №5
- •Основні теоретичні відомості
- •1.1 Основні поняття
- •1.2 Категорії даних
- •1.3 Відкриття і закриття ключів реєстру
- •1.4 Створення підключа у відкритому ключі реєстру
- •1.5 Отримання інформації з ключа реєстру
- •1.6 Перелічення списку значень для заданого ключа реєстру
- •1.7 Виявлення змін в гілці реєстру
- •1.8 Робота з налаштуваннями операційної системи через реєстр
- •2. Хід роботи
- •4. Завдання
- •5. Контрольні запитання
- •6. Список використаної літератури
- •Додаток 1
- •Лабораторна робота №6
- •1. Основні теоретичні відомості
- •Породження процесів
- •1.2 Породження потоків
- •2. Хід роботи
- •4. Індивідуальні завдання
- •5. Контрольні запитання
- •Для нотаток Для нотаток Для нотаток
1.2 Породження потоків
В традиційній моделі UNIX систем, якщо процес потребує, щоб деяка його частина була реалізована через іншу функціональну одиницю, то він викликає функцію fork() для створення нового процесу і переказує відповідну частину завдання цьому новому процесові. В такий спосіб працює більшість мережевих серверів в UNIX системах.
Протягом багатьох років такий принцип роботи досить вдало виправдовував себе, але виникають певні проблеми, пов'язані з викликом функції fork():
- виклик fork() є “дорогою” операцією. Весь вміст адресного простору батьківського процесу копіюється в адресний простір нового процесу разом з дескрипторами відкритих файлів та обробниками сигналів. Звичайно, реалізація fork() відбувається за принципом копіювання при-записі (copy-on-write, COW), у відповідності з яким копіювання сторінок пам’яті батьківського процесу в адресний простір породженого процесу відбувається лише за умови, коли породжений процес намагається змінити дані відповідного батьківського процесу. Така техніка дозволяє дещо підвищити ефективність системи, адже в більшості випадків після створення нового процесу батьківський процес одразу викликає exec().
- проблематичність при реалізації механізмів міжпроцесової взаємодії: якщо комунікація від батьківського процесу до породженого відбувається досить легко, то в зворотньому випадку виникають деякі труднощі.
Одним із способів породження потоків в ОС Linux є використання бібліотеки LinuxTreads, яка є реалізацією стандарту POSIX на обчислювальні потоки.
Однією з ідей стосовно потоків є те, що функція, яка створює новий потік, в якості параметра приймає вказівник на функцію, з якої починається новий потік обчислень.
Для запуску нового потоку використовується функція pthread_create():
#include <pthread.h>
int pthread_create(pthread_t * thread, pthread_attr_t *
attr, void * (*start_routine)(void *), void * arg);
pthread_t * thread - OUT - ідентифікатор новоствореного потоку;
pthread_attr_t * attr - IN - атрибути нового потоку;
void * (*start_routine)(void *) - IN - адреса функції, з якої почнеться новий потік;
void * arg - IN - адреса єдиного аргументу, що можна передати функції start_routine;
При успішному виконанні по адресі thread повертається ідентифікатор нового потоку і 0 у процес, що викликається; інакше у цей процес повертається ненульовий код помилки. Детальніше про код помилки у on-line документації по pthread_create.
Після того, як створено новий потік, виникає необхідність вказати викликаючому процесу не завершувати своє виконання, поки не завершиться цей новий потік. Для цього використовується функція pthread_join():
#include <pthread.h>
int pthread_join(pthread_t th, void **thread_return);
pthread_t th - IN - ідентифікатор потоку, на чиє закінчення потрібно зачекати
void **thread_return - OUT - адреса, по якій зберігається значення, повернуте потоком th при своєму закінченні.
При успішному виконанні по адресі thread_return зберігається значення, повернуте потоком th, і у викликаючий поток повертається 0. Інакше повертається ненульовий код помилки.
Ось приклад програми, що запускає новий обчислювальний потік, який у нескінченному циклі виводить в stdout свій ідентифікатор в системі.
#include <stdio.h>
#include <pthread.h>
#define DELAY 10000000
void *foo(void *);
int main(int argc, char **argv)
{
pthread_t tdi;
pthread_create(&tid, NULL, foo, 0);
pthread_join(tid, 0);
return 0;
}
void *foo(void *arg)
{
int i;
pthread_t tid = pthread_self();
for (;;)
{
printf("%s%d%s", "thread ", tid, "\n");
fflush(stdout);
for (i = 0; i < DELAY; i++)
;
}
}