QNX/UNIX: Анатомия параллелизма
Шрифт:
• Наконец, время выполнения целевой функции
func
включается в период одного «кругового пробега» цикла, то есть период T отсчитывается от концапредыдущего выполнения функции до началатекущего, а это не совсем то, что мы подразумевали при использовании термина «синхронное». • Более того, если время выполнения функции
func
достаточно флуктуирует от одного вызова до другого (например, из-за изменений данных, с которыми работает функция), то периоды вызовов начинают «гулять», а дисперсия периода результирующей последовательности вызовов func
становится
Ниже показано решение, свободное от многих из этих недостатков ( файл t3.cc). Приложение представляет собой тестовую программу, осуществляющую 3 цепочки выполнения различных целевых функций (
mon1
, mon2
, mon3
) с разными периодами для каждой цепочки (массив period[]
): Синхронизация выполнения участка кода
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <errno.h>
#include <iostream.h>
#include <sys/neutrino.h>
#include <sys/syspage.h>
#include <sys/netmgr.h>
#include <pthread.h>
#include <signal.h>
#include <algorithm>
static void out(char s) {
int policy;
sched_param param;
pthread_getschedparam(pthread_self, &policy, ¶m);
cout << s << param.sched_curpriority << flush;
}
// целевые функции каждой из последовательностей только
// выводят свой символ-идентификатор и следующий за ним
// приоритет, на котором выполняется целевая функция
static void mon1(void) { out('.'); }
static void mon2(void) { out('*'); }
static void mon3(void) { out('+'); }
// это всего лишь перерасчет временных интервалов,
// измеренных в тактах процессора (в наносекундах)
inline uint64_t cycles2nsec(uint64_t с) {
const static uint64_t cps =
// частота процессора
SYSPAGE_ENTRY(qtime)->cycles_per_sec;
return (с * 1000000000) / cps;
}
// структура, необходимая только для накопления статистики параметров
// ряда временных отметок: среднего, среднеквадратичного
отклонения,
// минимального и максимального значений
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;
Поделиться с друзьями: