// трюк преобразования над ее типом

  func = (void*(*)(void*))dofunc;

  int policy;

  // запомнить приоритет вызывающей программы

  // под этим приоритетом и вызывать целевую функцию

  pthread_getschedparam(pthread_self(), &policy, &param);

  st = statist;

  event.sigev_code = code++;

  event.sigev_notify = SIGEV_PULSE;

  // а вот это приоритет, с которым нужно будет пробуждаться от таймера!

  event.sigev_priority = priority;

  // создание таймера

  if (!(ok = (timer_create(CLOCK_REALTIME, &event, &timer) == 0))) return;

  // запуск отдельного потока, который по сигналу

  // таймера будет выполнять целевую функцию

  if (!(ok = (pthread_create(&tid, NULL, &syncthread, (void*)this) == EOK)))

   return;

  // и только после этого можно установить период срабатывания

  // таймера, после чего он фактически и запускается

  struct itimerspec itime;

  nsec2timespec(&itime.it_value, millisec * 1000000ull);

  itime it_interval = itime.it_value;

  if (!(ok = (timer_settime(timer, 0, &itime, NULL) == 0))) return;

 }

 // признак того, что объект создан успешно и его поток запущен:

 bool OK(void) { return ok; }

 bool statistic(void) { return st; }

};

int thrblock.code = _PULSE_CODE_MINAVAIL;

// функция потока объекта

void* syncthread(void *block) {

 thrblock *p = (thrblock*)block;

 struct _pulse buf;

 pthread_attr_t attr;

 while(true) {

  // ожидание пульса от периодического таймера объекта

  MsgReceivePulse(p->chid, &buf, sizeof(struct _pulse), NULL);

  pthread_attr_init(&attr);

  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

  // восстановить приоритет целевой функции до уровня того,

  // кто ее устанавливал, вызывая конструктор

  pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

  pthread_attr_setschedparam(&attr, &p->param);

  // запуск целевой функции в отдельном 'отсоединенном' потоке

  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 << ' ' << p->num << ' => ' << p->mean / n2m << ' [' <<

   p->tmin / n2m << '...' << p->tmax / n2m << '] ~' << p->disp / n2m <<

   ' (' << p->disp / p->mean * 100 << '%)' << endl;

 }

 return EXIT_SUCCESS;

}

Вся функциональность программы сосредоточена в одном классе — thrblock, который может в неизменном виде использоваться для разных приложений. Необычной особенностью объекта этого класса является то, что он выполнен в технике «активных объектов», навеянной поверхностным знакомством с языками программирования школы Н. Вирта — ActiveOberon и Zormon. В ней говорится, что конструктор такого объекта не только создает объект данных, но и запускает (как вариант) отдельный поток

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату