Литмир - Электронная Библиотека
Содержание  
A
A

Если поток много раз вытесняется в период своей работы с основным приоритетом, то его выполнение может превратиться в многократное колебание с высокой частотой между основным и фоновым приоритетами. Поэтому в 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)

   cout << "thread create error", exit(EXIT_FAILURE);

 // и дожидаться их завершения ...

 for (int i = 0; i < T; i++)

  pthread_join(tid[i], NULL);

 exit(EXIT_SUCCESS);

}

Результаты выполнения программы:

# nice -n-19 p5t -n100

2       : cycles - 79490; on sched - 397

3       : cycles - 78350; on sched — 391

# nice -n-19 p5t -n1000

2       : cycles - 753269; on sched - 376

3       : cycles - 752069; on sched - 376

# nice -n-19 p5t -n10000

2       : cycles - 7494255; on sched - 374

3       : cycles - 7493225; on sched - 374

# nice -n-19 p5t -n100000

2       : cycles - 74897795; on sched - 374

3       : cycles - 74895800; on sched — 374

# nice -n-19 p5t -n1000000

2       : cycles - 748850811, on sched - 374

3       : cycles - 748850432; on sched - 374

Как и в случае с процессами, результаты отличаются очень высокой устойчивостью при изменении «объема вычислений» на 4 порядка, однако по своим величинам значения для потоков почти в 2 раза меньше, чем для процессов (стр. 45).

Завершение потока

Как и в случае обсуждавшегося ранее завершения процесса, для потоков мы будем отчетливо различать случаи:

• «естественного» завершения выполнения потока из кода самого потока;

• завершения потока извне, из кода другого потока или по сигналу. Для этого действия, в отличие от «естественного» завершения, будем использовать другой термин — отмена.

Завершение потока происходит при достижении функцией потока своего естественного конца и выполнения оператора

return
(явно или неявно) или выполнения потоком вызова:

29
{"b":"155449","o":1}