Програмування в ace: рівень інтерфейсних фасадів, багатозадачність і багатопоточність

Рівень інтерфейсних фасадів
Програмування в ACE: рівень інтерфейсних фасадів, багатозадачність і багатопоточність

Описані вище механізми паралелізму реалізовані в ACE у вигляді інтерфейсних фасадів. Таким чином, ми піднімаємося з рівня адаптації до операційної системи на рівень фасадів ACE, інкапсулюючих API операційної системи. Виникає питання: а для чого потрібно використовувати фасади ACE, чи не простіше нам використовувати API операційної системи і сокети для реалізації конкретного завдання? Відповідь лежить на поверхні - по-перше, ми створюємо легко переносимо код, який можна буде використовувати повторно, а, по-друге, замість небезпечних з точки зору типо-безпеки дескрипторів функцій API, ми використовуємо инкапсулирующие їх фасади ACE.

багатозадачність

Як відомо, створення нового завдання здійснюється в POSIX-сумісних операційних системах за допомогою функції fork () (в Windows це можна зробити за допомогою функції CreateProcess ()). Замість цього ACE пропонує клас ACE_Process, за допомогою якого можна створювати процеси і керувати ними. За допомогою класу ACE_Process_Option програміст може задавати опції процесу, такі як командний рядок, змінні оточення, робочий каталог і їм подібні. Створимо утиліту, яка запускає програму, ім`я якої зазначено в якості аргументу командного рядка.
#include
#include

int main (int argc, char * argv [])
{
if (argcspawn ( process1, options);
// Чекаємо завершення всіх процесів, асоційованих з групою
return pPM-gt; wait (ACE_Time_Value :: max_time);
}

Нить

На відміну від багатозадачності, багатопоточність дозволяє різним потокам виконання працювати в єдиному адресному просторі процесу. І в більшості випадків многопоточность є більш зручною схемою для створення додатків, які обробляють множинні клієнтські запити. При програмуванні кроссплатформенних багатопоточних додатків програмісти стикаються не тільки з відмінностями в семантиці потокових API, але і з різними ідеологіями многопоточности. Наприклад, в Linux потоки є процесами особливого типу - легкими (lightweight) процесами. Вони створюються як дочірні процеси головного процесу. У Windows ми маємо головний процес, який є певним контейнером для потоків програми. В ACE потоки створюються і управляються за допомогою класу ACE_Thread_Manager. Аналогічно до вищеописаного менеджеру процесів, цим класом можна користуватися як Сінглтоном або створювати кілька примірників менеджера потоків для визначення різних груп потоків в рамках одного процесу. Напишемо невелику програму, яка створює три нескінченно виконуються потоку, і закриває їх після деякої паузи.
#include
#include

unsigned long thread (void * p)
{
// Імітуємо роботу потоку
ACE_OS :: printf ( "Hi there. I am #% i thread n", p);
// По ідеї ми повинні «заснути» на нескінченний час
// Але виклик cancel_all () в кінці main () закриває всі потоки
ACE_OS :: sleep (ACE_Time_Value :: max_time);
return 0;
}

int main (int argc, char * argv [])
{
// Створюємо три потоку
ACE_Thread_Manager * pTM = ACE_Thread_Manager :: instance ();
pTM-gt; spawn (thread, (void *) 0, THR_SCOPE_SYSTEM);
pTM -gt; spawn (thread, (void *) 1, THR_SCOPE_SYSTEM);
pTM -gt; spawn (thread, (void *) 2, THR_SCOPE_SYSTEM);
// Імітуємо якусь роботу основного потоку
ACE_OS :: sleep (1);
// Завершуємо все потоки
pTM-gt; cancel_all ();
// Чекаємо завершення всіх потоків



return pTM-gt; wait ( ACE_Time_Value :: max_time);
}

Одним з параметрів методу spawn () менеджера потоків є пріоритет потоку, і за замовчуванням це значення дорівнює ACE_DEFAULT_THREAD_PRIORITY. За допомогою класу ACE_Sched_Params можна вибирати потрібний пріоритет виконання і встановлювати його за допомогою функції sched_params з простору імен ACE_OS. Базовий пріоритет виконання для всіх потоків програми можна встановити на самому початку її роботи в функції main (). Таким чином, всі новостворювані потоки будуть виконуватися з цим пріоритетом. Нижченаведений код демонструє, як можна встановити пріоритет виконання.
#include
#include

int main (int argc, char * argv [])
{
ACE_Sched_Params schedParams (ACE_SCHED_FIFO,
ACE_Sched_Params :: priority_min (ACE_SCHED_FIFO),
ACE_SCOPE_PROCESS);
ACE_OS :: sched_params (schedParams);
return 0;
}

Синхронізація

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

Всі класи синхронізації надають уніфікований інтерфейс ACE_LOCK. Напишемо програму, основний потік якої змінює значення глобальної змінної, а допоміжний виводить її значення в консоль, коли вона змінюється. Фактично ми змоделюємо один з найпоширеніших випадків, коли потрібно синхронізувати роботу потоків.
#include



#include
#include

// Глобальний лічильник
static int gCounter (0);

// М`ютекс
static ACE_Thread_Mutex gMutex;

unsigned long thread (void * p)
{
int oldValue (-1);
while (1)
{
// запитуваний блокування
if (gMutex.acquire_read ()! = - 1)
{
// Якщо значення лічильника було інкрементіровать, виводимо його
if (gCountergt; oldValue)
{
ACE_OS :: printf ( "Counter is% i n", gCounter);
oldValue = gCounter;
}
}
// Знімаємо блокування
gMutex.release ();
}
return 0;
}

int main (int argc, char * argv [])
{
ACE_Thread_Manager * pTM = ACE_Thread_Manager :: instance ();
// Створюємо три потоку
int id;
id = pTM-gt; spawn (thread, (void *) 0, THR_SCOPE_SYSTEM);
if (id == - 1)
{
ACE_OS :: printf ( "Unable to create thread n");
return -1;
}
int i (10);
while (i)
{
// запитуваний блокування
if (gMutex.acquire_write ()! = - 1)
{
++gCounter;
}
// Знімаємо блокування
gMutex.release ();
--i;
// Імітуємо роботу програми
ACE_OS :: sleep (1);
}
// Завершуємо все потоки
pTM -gt; cancel_all ();
// Чекаємо завершення всіх потоків
return pTM -gt; wait ( ACE_Time_Value :: max_time);
}


ІНШЕ

Juce: многопоточность фото

Juce: многопоточность

Нить в Juce реалізується класом Thread. Як і в багатьох інших тулкіта, це повністю віртуальний клас, наслідуючи який…

Sdl + mingw = дружба! фото

Sdl + mingw = дружба!

Відео: SDL 2 Tutorial 1c [SETUP] Windows and MinGW Setup Мабуть, SDL - найпопулярніша бібліотека для створення…

Sdl: збірка за допомогою make фото

Sdl: збірка за допомогою make

Відео: C. Урок 12. Компіляція і система збирання (gcc, make)Етап 4. Складання за допомогою make Наведу мінімальний…

Ultimate ++: схеми баз даних фото

Ultimate ++: схеми баз даних

Відео: Бази даних, лекція №1 (2013) Об`єкти SqlExp кардинально полегшують створення запитів, але створення самих…

Програмування в ace фото

Програмування в ace

Відео: Rpg Maker VX Ace [MV] урок 1 (Створення персонажа) RUS Розробка розподіленої крос-платформної програмної…

Ultimate ++: перша програма фото

Ultimate ++: перша програма

Відео: Уроки C # (C sharp) | # 3 - Перша програма на C # Перейдемо до реального прикладу. Напишемо просту марну…

» » Програмування в ace: рівень інтерфейсних фасадів, багатозадачність і багатопоточність