Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Metodychka-lab_OS.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
1.35 Mб
Скачать

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++)

;

}

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]