Рис. 2.6. Периодическое выполнение спорадической задачи
Если поток много раз вытесняется в период своей работы с основным приоритетом, то его выполнение может превратиться в многократное колебание с высокой частотой между основным и фоновым приоритетами. Поэтому в QNX 6.2.1 в параметрах для спорадической диспетчеризации можно установить (ограничить) максимальное количество пополнений бюджета за период.
Как уже описывалось выше, структура
shed_param
содержит
в своем составе, в частности, еще и структуру параметров для спорадической диспетчеризации (при других типах диспетчеризации эта часть не используется):
struct {
_INT32 __ss_low_priority;
_INT32 __ss_max_repl;
struct timespec __ss_repl_period;
struct timespec __ss_init_budget;
} __ss;
где
low_priority
— фоновый приоритет;
max_repl
— максимальное количество пополнений бюджета за период;
repl_period
— период пополнения бюджета и
init_budget
— начальный бюджет.
Соображения производительности
Выполним «симметричный» тест аналогично тому, как это делалось для переключения контекстов процессов (стр. 44), но теперь применительно к потокам ( файл p5t.cc). При этом мы постараемся максимально сохранить принципы функционирования, имевшие место в приложении «Затраты на взаимное переключение процессов» ( файл p5.сс) (естественно, из-за принципиального различия механизмов тексты кодов будут существенно отличаться).
Затраты на взаимное переключение потоков
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <iostream.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/neutrino.h>
unsigned long N = 1000;
// потоковая функция:
void* threadfunc(void* data) {
uint64_t t = ClockCycles;
for (unsigned long i = 0; i < N; i++) sched_yield;
t = ClockCycles - t;
// дать спокойно завершиться 2-му потоку до начала вывода
delay(100);
cout << pthread_self << "\t: cycles - " << t
<< ", on sched - " << (t / N) / 2 << endl;
return NULL;
}
int main(int argc, char* argv[]) {
int opt, val;
while ((opt = getopt(argc, argv, "n:")) != -1) {
switch(opt) {
case 'n': //
переопределения числа переключений
if (sscanf(optarg, "%i", &val) != 1)
cout << "parse command line error" << endl, exit(EXIT_FAILURE);
if (val > 0) N = val;
break;
default:
exit(EXIT_FAILURE);
}
}
const int T = 2;
pthread_t tid[T];
// создать взаимодействующие потоки
for (int i = 0; i < T; i++)
if (pthread_create(tid + i, NULL, threadfunc, NULL) != EOK)
Как и в случае с процессами, результаты отличаются очень высокой устойчивостью при изменении «объема вычислений» на 4 порядка, однако по своим величинам значения для потоков почти в 2 раза меньше, чем для процессов (стр. 45).
Завершение потока
Как и в случае обсуждавшегося ранее завершения процесса, для потоков мы будем отчетливо различать случаи: