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

на главную - закладки

Жанры

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

return res;

}

private:

std::queue<T> data_queue;

event data_event;

pthread_mutex_t _mutex;

};

На первый взгляд задача очевидна: надо не допустить одновременного исполнения двух участков кода. Почему же не воспользоваться семафором, как мы описывали, когда рассказывали о способах его применения? Дело в том, что мы хотели получить универсальное средство передачи

данных между потоками, не зависящее от допущений о приоритетах потоков и степени их зависимости. Когда мы строим систему реального времени, вопрос взаимного неявного влияния разных потоков на выполнение друг друга становится очень важным. Мы уже неоднократно упоминали эффект инверсии приоритетов и те способы, которыми можно ее избежать, используя мьютекс для защиты эксклюзивно используемого кода.

Сравнение и эффективность

В этом месте временно прервем наше последовательное повествование: мы закончили рассмотрение двух наиболее известных, важных и применяемых примитивов синхронизации — семафора и мьютекса. Теперь сделаем короткую остановку и проведем их взаимное сравнение, а также попробуем на примерах оценить затраты процессорной производительности, требуемые этими механизмами.

Дело в том, что на первый взгляд эти два механизма в высшей степени подобны, особенно если речь заходит о бинарном семафоре, принимающем значения счетчика 0 либо 1. Настолько подобны, что и в обсуждениях, и даже в неспециальной литературе можно встретить утверждения, что это «одно и то же». Сейчас мы увидим, что эти два сходных механизма различаются всем: и затратами процессорного времени на их обслуживание, и целями и задачами, которые они призваны решать, и временем жизни… Начнем с простой оценки затрат процессорного времени на обслуживание каждого из механизмов, после чего остальные различия станут нам намного понятнее.

Для проведения таких оценок используем уже применявшуюся нами схему «симметричных» тестов. Почему именно их? Да, здесь нам не требуются в явном виде обменные операции потоков, но воспользуемся «симметричными» тестами просто в силу минимальных переделок того, что уже было написано ранее. Итак, первый вариант теста для мьютекса ( файл sy20m.cc):

Скоростные показатели мьютекса

unsigned long N = 1000;

static pthread_barrier_t bstart;

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

static bool debug = false;

static char* str;

static volatile int ind = 0;

void* threadfunc(void* data) {

pthread_barrier_wait(&bstart);

unsigned long i = 0;

char tid[8];

sprintf(tid, "%d", pthread_self);

uint64_t t = 0, t1;

while (i++ != N) {

t1 = ClockCycles;

pthread_mutex_lock(&mutex);

if (debug) str[ind++] = *tid;

pthread_mutex_unlock(&mutex);

t += ClockCycles - t1;

sched_yield;

}

cout << pthread_self << "\t: cycles - "

<< t << ", on mutex - " << t / N << endl;

return NULL;

}

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

int opt, val;

while ((opt = getopt(argc, argv, "n,v")) != -1) {

switch (opt) {

case 'n':

if (sscanf(optarg, "%i", &val) != 1)

cout << "parse command line error" << endl, exit(EXIT_FAILURE);

if (val > 0) N = val;

break;

case 'v':

debug = true;

break;

default:

exit(EXIT_FAILURE);

}

}

if (debug) str = new char[2 * N + 1];

const int T = 2;

pthread_t tid[T];

if (pthread_barrier_init(&bstart, NULL, T) != EOK)

perror("barrier init"), exit(EXIT_FAILURE);

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

if (pthread_create(tid + i, NULL, threadfunc, NULL) != EOK)

perror("thread create"), exit(EXIT_FAILURE);

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

pthread_join(tid[i], NULL);

if (debug) {

str[ind] = '\0';

cout << str << endl;

delete [] str;

}

exit(EXIT_SUCCESS);

}

Результаты

выполнения этого теста:

# sy20m -n100000

3 : cycles - 14644442, on mutex - 146

2 : cycles - 14614219; on mutex - 146

# sy20m -n1000000

3 : cycles - 146505047; on mutex - 146

2 : cycles - 146388673; on mutex - 146

Модифицируем программу, используя вместо мьютекса неименованный бинарный семафор. Для того чтобы не загромождать текст практически тем же кодом, перечислим только необходимые при этом изменения ( файл sy20s.cc):

Поделиться:
Популярные книги

Газлайтер. Том 8

Володин Григорий
8. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 8

На Ларэде

Кронос Александр
3. Лэрн
Фантастика:
фэнтези
героическая фантастика
стимпанк
5.00
рейтинг книги
На Ларэде

Охота на попаданку. Бракованная жена

Герр Ольга
Любовные романы:
любовно-фантастические романы
5.60
рейтинг книги
Охота на попаданку. Бракованная жена

Кай из рода красных драконов

Бэд Кристиан
1. Красная кость
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Кай из рода красных драконов

Хозяйка Проклятой Пустоши. Книга 2

Белецкая Наталья
2. Хозяйка Проклятой Пустоши
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Хозяйка Проклятой Пустоши. Книга 2

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Потусторонний. Книга 2

Погуляй Юрий Александрович
2. Господин Артемьев
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Потусторонний. Книга 2

Чапаев и пустота

Пелевин Виктор Олегович
Проза:
современная проза
8.39
рейтинг книги
Чапаев и пустота

Солнечный корт

Сакавич Нора
4. Все ради игры
Фантастика:
зарубежная фантастика
5.00
рейтинг книги
Солнечный корт

Лютая

Шёпот Светлана Богдановна
Любовные романы:
любовно-фантастические романы
6.40
рейтинг книги
Лютая

Ведьмак (большой сборник)

Сапковский Анджей
Ведьмак
Фантастика:
фэнтези
9.29
рейтинг книги
Ведьмак (большой сборник)

Наследие Маозари 4

Панежин Евгений
4. Наследие Маозари
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Наследие Маозари 4

Ученик

Губарев Алексей
1. Тай Фун
Фантастика:
фэнтези
5.00
рейтинг книги
Ученик

Начальник милиции. Книга 5

Дамиров Рафаэль
5. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 5