Студопедия  
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Програмний інтерфейс керування потоками POSIX

Читайте также:
  1. UNIX, стандартизация операционных систем и POSIX
  2. Елементи інтерфейсу вікон
  3. Елементи інтерфейсу користувача Excel
  4. З яких частин складається програмний компонент?
  5. Засоби подання знань і стратегії керування
  6. Засоби управління графічним інтерфейсом користувача
  7. Интерфейс POSIX. Семейство стандартов POSIX.
  8. Керування адресним простором під час створення процесів
  9. Керування персоналом у Японії
  10. Керування персоналом у Японії

Керування потоками є частиною стандарту POSIX з 1996 року, відповідний програмний інтерфейс дістав назву потоки POSIX (POSIX threads). Цей стандарт
реалізовано у більшості сучасних UNIX-сумісних систем, у Linux його підтримка
була частково реалізована в бібліотеці LinuxThreads і значно повніше — у бібліотеці NPTL.

У цьому розділі ми зупинимося на базових засобах керування потоками POSIX,
відклавши розгляд засобів синхронізації до розділу 5.

Усі типи даних і функції, визначені стандартом, мають префікс pthread_, для
їхнього використання необхідно підключати заголовний файл pthread.h.

Створення потоків POSIX

Щоб додати новий потік у поточний процес, у POSIX використовують функцію
pthread_create() із таким синтаксисом:

#include<pthread.h>

int pthread_create(pthread__t *th. pthread_attr_t *attr,

void *(*thread_fun)(void *). void *arg);

Розглянемо параметри цієї функції:

♦ th — покажчик на заздалегідь визначену структуру типу pthread_t, яка далі буде передана в інші функції роботи з потоками; далі називатимемо її дескриптором потоку (thread handle);

♦ attr — покажчик на структуру з атрибутами потоку (для використання атрибутів за замовчуванням потрібно передавати нульовий покажчик, деякі атрибути розглянемо пізніше);

♦ thread__fun - покажчик на функцію потоку, що має описуватися як

void *mythread_fun(void *value) {

// виконання коду потоку

}

♦ arg — дані, що передаються у функцію потоку (туди вони потраплять як параметр value).

Ось приклад створення потоку POSIX:

#include<pthread.h>

// функція потоку

void *thread_fun(void *num) {

printf ("потік номер %d\n". (int)num);

}

// ...

pthread_t th;

// створюємо другий потік

pthread_create (&th. NULL. thread_fun, (void *)++thread_num);

// тут паралельно виконуються два потоки

Для потоків, створених у такий спосіб, розмір стека задають за замовчуванням. Крім того, після завершення їх обов'язково треба приєднати.

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

Завершення потоків POSIX

Для завершення потоку достатньо дійти до кінця його функції потоку thread_fun()
або викликати з неї pthread_exit():

#include<pthread.h>

void pthread_exit(void *retval);

Параметр retval задає код повернення. Наведемо приклад завершення потоку:

void *thread_fun(void *num) {

printf ("потік номер %d\n", (int)num);
pthread_exit (0);

}

Для коду початкового потоку програми є дві різні ситуації:

♦ виконання оператора return або виконання всіх операторів до кінця main () завершує весь процесу при цьому всі потоки теж завершують своє виконання;

♦ виконання функції pthread_exit() усередині функції main () завершує тільки
початковий потік, ця дія не впливає на інші потоки у програмі - вони продов-
жуватимуть виконання, поки самі не завершаться.

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

Приєднання потоків POSIX

Для очікування завершення виконання потоків використовують функцію pthread
_ join(). Вона має такий синтаксис:

int pthread_ join(pthread_t th, void **status);

Ця функція блокує потік, де вона була викликана, доти, поки потік, заданий дескриптором th, не завершить своє виконання. Потік, на який очікують, має існувати
в тому самому процесі й не бути від'єднаним. Якщо status не є нульовим покажчиком, після виклику він вказуватиме на дані, повернені потоком (аргумент
функції pthread_exit()). Якщо потік уже завершився до моменту виклику функції
pthread_ join (), його інформація має бути зчитана негайно.

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

Розглянемо приклад приєднання потоку. Припустимо, що треба асинхронно
запустити доволі тривалий запит до бази даних, виконати паралельно з ним деяку
роботу (наприклад, відобразити індикатор виконання), після чого дочекатися результатів запиту. Пропоноване рішення зводиться до створення окремого потоку для виконання запиту (потоку-помічника, helper thread) і до очікування його завершення у базовому потоці. Ось приблизний програмний код:

struct result_data {

// інформація з бази даних

}:

void *query_fun(void *retval) {
struct result_data db_result;

// одержати дані з бази (search_db() тут не задаємо)
db_result = search_db(...):

// визначаємо результат

*(struct result_data *)retval = db_result;

pthread_exit(0);

}

int main () {

pthread_t query_th;
void *status;

struct result_data query_res;

// почати виконувати запит паралельно з основним кодом main ()
pthread_create(&query_th, NULL. query__fun, &query_res);

// вчинити деякі дії паралельно з виконанням запиту
// тут два потоки виконуються паралельно

pthread_ join(query_th. &status); // дочекатися результату запиту
// тепер можна безпечно використати результат запиту query_res
return 0:

}

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

Від’єднані потоки. Задання атрибутів потоків POSIX

Для того, щоб отримати від'єднаний потік, треба задати відповідні атрибути потоку, виконавши такі дії.

1. Описати змінну для їхнього зберігання (атрибути потоку відображає структура
даних pthread_attr_t):

pthread_attrj; attr;

2. Ініціалізувати цю змінну так:
pthread_attrjnit(&attr);

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

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

pthread_attr_setdetachstate(pthread_attr_t attr, int detachstate);

Другим параметром може бути одне зі значень: PTHREAD_CREATE_JOINABLE (приєднуваний потік); PTHREAD_CREATEJ)ETACHED (від'єднаний потік).

Ось приклад задання атрибута і його використання під час створення від’єднаного потоку:

pthread_attr_init(&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&th. &attr, ...);

Завершуються такі потоки виходом із функції потоку.

3.9. Керування процесами у Windows ХР

Поняття процесу й потоку у Windows ХР чітко розмежовані. Процеси в даній
системі визначають «поле діяльності» для потоків, які виконуються в їхньому адресному просторі. Серед ресурсів, з якими процес може працювати прямо, відсутній процесор — він доступний тільки потокам цього процесу. Процес, проте, може
задати початкові характеристики для своїх потоків і тим самим вплинути на їхнє
виконання.


Дата добавления: 2014-12-20; просмотров: 20 | Нарушение авторских прав




lektsii.net - Лекции.Нет - 2014-2021 год. (0.009 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав