// структура, необходимая только для накопления статистики параметров
// ряда временных отметок: среднего, среднеквадратичного отклонения,
// минимального и максимального значений
struct timestat {
private:
uint64_t prev;
public:
uint64_t num;
double mean, disp, tmin, tmax;
timestat(void) {
mean = disp = tmin = tmax = 0.0;
num = 0;
}
// новая временная отметка в ряду:
void operator++(void) {
uint64_t next = ClockCycles(), delta;
if (num i= 0) {
double delta = cycles2nsec(next — prev);
if (num == 1) tmin = tmax = delta;
else tmin = min(tmin, delta), tmax = max(tmax, delta);
mean += delta;
disp += delta * delta;
}
prev = next;
num++;
}
// подвести итог ряда;
void operator !(void) {
mean /= (num - 1);
disp = sqrt(disp / (num - 1) - mean * mean);
}
}
// предварительное описание функции потока объекта
void* syncthread(void*);
class thrblock {
private:
static int code;
bool ok, st;
public:
pthread_t tid;
struct sigevent event;
timer_t timer;
int chid;
void* (*func)(void*);
sched_param param;
// структура только для статистики:
timestat sync;
// конструктор класса - он не только инициализирует структуру данных
// создаваемого объекта, но и запускает отдельный поток для его исполнения
thrblock(
// параметры конструктора
// - целевая функция последовательности
void (*dofunc)(void);
// - период ее синхронизации
unsigned long millisec;
// - приоритет возбуждения синхросерии
unsigned short priority;
// - копить ли статистику временных интервалов?
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;
// и только после этого можно установить период срабатывания