QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// восстановить приоритет целевой функции до уровня того,
// кто ее устанавливал, вызывая конструктор
<b> pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);</b>
<b> pthread_attr_setschedparam(&attr, &p->param);</b>
// запуск целевой функции в отдельном "отсоединенном" потоке
pthread_create(NULL, &attr, p->func, NULL);
if (p->statistic()) ++p->sync;
}
}
// 'пустой' обработчик сигнала SIGINT (реакция на ^С)
inline static void empty(int signo) {}
int main(int argc, char **argv) {
// с этой точки стандартная реакция на ^С отменяется...
signal(SIGINT, empty);
// массив целевых функций
void(*funcs[])(void) = { &mon1, &mon2, &mon3 };
// периоды их синхросерий запуска
int period[] = { 317, 171, 77 };
// приоритеты, на которых отрабатывается реакция
// синхросерий на каждый из таймеров синхросерий
int priority[] = { 15, 5, 25 };
int num = sizeof(funcs) / sizeof(*funcs);
// запуск 3-х синхронизированных последовательностей
// выполнения (созданием объектов)
thrblock** tb = new (thrblock*)[num];
for (int i = 0; i < num; i++) {
tb[i] = new thrblock(funcs[i], period[i],
priority[i], true);
if (!tb[i]->OK())
perror("synchro thread create"), exit(EXIT_FAILURE);
}
// ... а теперь ожидаем ^С.
pause();
// подсчет статистики и завершение программы
cout << endl << "Monitoring finalisation!" << endl;
// вывод временных интервалов будем делать в миллисекундах:
const double n2m = 1000000.;
for (int i = 0; i < num, i++) {
timestat *p = &tb[i]->sync;
!(*p); // подсчет статистики по объекту
cout << i << 't' << p->num << "t=> " << p->mean / n2m << " [" <<
p->tmin / n2m << "..." << p->tmax / n2m << "]t~" << p->disp / n2m <<
" (" << p->disp / p->mean * 100 << "%)" << endl;
}
return EXIT_SUCCESS;
}
Вся функциональность программы сосредоточена в одном классе — thrblock, который может в неизменном виде использоваться для разных приложений. Необычной особенностью объекта этого класса является то, что он выполнен в технике «активных объектов», навеянной поверхностным знакомством с языками программирования школы Н. Вирта — ActiveOberon и Zormon. В ней говорится, что конструктор такого объекта не только создает объект данных, но и запускает (как вариант) отдельный поток выполнения для каждого создаваемого объекта. В нашем случае задача потоковой функции состоит в вызове целевой функции, адрес которой был передан конструктору объекта в качестве одного из параметров. [26]
Ниже представлены отличия нашей реализации от простого цикла с задержкой, обсуждавшейся выше (помимо исправлений очевидных недостатков):
• Для каждого синхронизирующего таймера установлен свой приоритет «пробуждения», и он может быть достаточно высоким, для того чтобы предотвратить вытеснение этого синхронизирующего потока.
• После «пробуждения» по таймеру запускается целевая функция, но выполняется это отдельным потоком, причем потоком «отсоединенным». Другими словами, процесс выполнения целевой функции никак не влияет на общую схему синхронизации.
• Перед запуском целевой функции выполняющему ее потоку восстанавливается приоритет породившего потока (но не потока обслуживания таймера!), ведь нам не нужно, чтобы целевая функция, тем более, возможно и не очень значимая, как в нашем примере, могла влиять вытеснением на процессы синхронизации.
Запустим наше тестовое приложение:
# t3
+10+10*10+10+10.10*10+10+10*10+10+10.10*10+10+10+10*10+10.10+10*10+10+10*10+10.10+10*10+10+10*10+10.10+10+10*10+10+10+10.10+10+10*10+10+10.10*10+10+10+10*10+10.10+10*10+10+10*10+10+10.10*10+10+10*10+10+10.10+10*10+10+10*10+10.10+10*10+10+10*10+10.10+10+10*10+10+10*10^C
Monitoring finalisation!
0 32 => 316.919 [316.867...317.895] ~0.178511 (0.056327%)
1 59 => 170.955 [168.583...173.296] ~0.92472 (0.540914%)
2 132 => 76.9796 [76.942...77.9524] ~0.085977 (0.111688%)
Первое, что мы должны отметить, — это очень приличную точность выдержки периода синхронизации (последняя колонка вывода). Для того чтобы убедиться в том, что целевая функция при этом выполняется под приоритетом породившего ее потока, закомментируем строки, выделенные жирным шрифтом в коде программы:
# t3
+25+25*5+25+25.15*5+25+25*5+25+25.15*5+25+25+25*5+25.15+25*5+25+25*5+25.15+25*5+25+25*5*5+25.15+25+25*5+25+25*5.15+25+25*5+25+25.15*5+25+25+25*5+25.15+25*5+25+25*5+25+25.15*5+25+25*5+25+25^C
Monitoring finalisation!
0 32 => 316.919 [316.797...317.915] ~0.185331 (0.0584792%)
Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение QNX/UNIX: Анатомия параллелизма - Цилюрик Олег Иванович, относящееся к жанру Интернет. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.


