QNX/UNIX: Анатомия параллелизма
Шрифт:
// - копить ли статистику временных интервалов?
bool statist = false
) {
// создание канала для получения уведомлений от таймера
if (!(ok = ((chid = ChannelCreate(0)) >= 0))) return;
// создать соединение по каналу, которое будет использовать таймер
event.sigev_coid =
ConnectAttach(ND_LOCAL_NODE, 0, chid, NTO_SIDE_CHANNEL, 0);
if (!(ok = (event.sigev_coid >= 0))) return;
//
занести целевую функцию, заодно выполнив
// трюк преобразования над ее типом
func = (void*(*)(void*))dofunc;
int policy;
// запомнить приоритет вызывающей программы
// под этим приоритетом и вызывать целевую функцию
pthread_getschedparam(pthread_self, &policy, ¶m);
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.;
Поделиться с друзьями: