Чтение онлайн

ЖАНРЫ

QNX/UNIX: Анатомия параллелизма
Шрифт:

class dbase : public list<element> {

static const int READ_DELAY = 1, WRITE_DELAY = 2;

public:

// операция "добавить в базу данных"

void add(const element& e) {

int pos = size * rand / RAND_MAX;

list<element>::iterator p = begin;

for (int i = 0; i < pos; i++) p++;

insert(p, e);

delay(WRITE_DELAY);

}

//
операция "найти в базе данных"

int pos(const element& e) {

int n = 0;

for (list<element>::iterator i = begin; i != end; i++, n++)

if (*i == e) {

delay(READ_DELAY);

break;

}

if (n == size) n = -1;

return n;

}

} data;

inline element erand(unsigned long n) {

return (element)((n * rand) / RAND_MAX);

}

inline bool wrand(double p) {

return (double)rand / (double)RAND_MAX < p;

}

int main(int argc, char *argv[]) {

// общее число обращений приложения к базе данных

static unsigned long n = 1000;

// вероятность обновления базы данных при обращении

static double p = .1;

unsigned long m;

if (argc > 1 && (m = atoll(argv[1])) ! = 0) n = m;

double q;

if (argc > 2 && (q = atof(argv[2])) != 0) p = q;

// начальное заполнение базы данных

for (int i = 0; i < n; i++) data.add(erand(n));

// тактовая частота процессора (для измерения времени)

const uint64_t cps = SYSPAGE_ENTRY(qtime)->cycles_per_sec;

// последовательность n обращений к базе данных,

// из них p*n требуют обновления списка, а остальные

// (1-p)*n требуют только выборки данных:

uint64_t t = ClockCycles;

for (int i = 0; i < n; i++) {

element e = erand(n);

if (!wrand(p)) data.pos(e);

else data.add(e);

}

t = ((ClockCycles - t) * 1000000000) / cps;

cout << "evaluation time: " << (double)t / 1.E9

<< " sec." << endl;

return EXIT_SUCCESS;

}

Перед

нами простейшая последовательная программа, которая массированно читает свою базу данных и изредка ее модифицирует. Для выполнения реальных операций чтения/записи данных программе необходимо выполнять некоторые достаточно продолжительные операции. В приведенном коде эти операции имитируются задержками
delay(WRITE_DELAY)
и
delay(READ_DELAY)
.

Возникает совершенно естественное желание преобразовать последовательные запросы к данным в параллельные ( файл sy11.cc). Для этого преобразуем структуру списка элементов, с которым работаем:

class dbase : public list<element> {

static const int READ_DELAY = 1, WRITE_DELAY = 2;

pthread_mutex_t loc;

public:

dbase(void) { pthread_mutex_init(&loc, NULL); }

~dbase(void) { pthread_mutex_destroy(&loc); }

void add(const elements e) {

pthread_mutex_lock(&loc);

int pos = size * rand / RAND_MAX;

list<element>::iterator p = begin;

for (int i = 0; i < pos; i++) p++;

insert(p, e);

delay(WRITE_DELAY);

pthread_mutex_unlock(&loc);

}

int pos(const elements e) {

int n = 0;

pthread_mutex_lock(&loc);

for (list<element>::iterator i = begin; i != end; i++, n++)

if (*i == e) {

delay(READ_DELAY);

break;

}

pthread_mutex_unlock(&loc);

if (n == size) n = -1;

return n;

}

} data;

А в вызывающей программе цикл запросов к данным преобразуем в:

pthread_t *h = new pthread_t[n];

uint64_t t = ClockCycles;

for (int i = 0; i < n; i++) {

element e = erand(n);

pthread_create(h + i, NULL, wrand(p) ? add : pos, (void*)e);

}

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

pthread_join(h[i], NULL);

t = ((ClockCycles - t) * 1000000000) / cps;

delete h;

А используемые этим фрагментом функции потоков определим как:

Поделиться с друзьями: