Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform | страница 38
Ниже приведен однопоточный вариант:
>int main (int argc, char **argv) {
> int x1;
> ... // Выполнить инициализации
> for (x1 = 0; x1 < num_x_lines; x1++) {
> do_one_line(x1);
> }
> ... // Вывести результат
>}
Здесь мы видим, что программа итеративно по всем значениям рассчитает необходимые растровые строки.
В многопроцессорных системах эта программа будет использовать только один из процессоров. Почему? Потому что мы не указали операционной системе выполнять что-либо параллельно. Операционная система не настолько умна, чтобы посмотреть на программу и сказать: «Эй, секундочку! У нас ее 4 процессора, и похоже, что у нас тут несколько независимых потоков управления. Запущу-ка я это на всех 4 процессорах сразу!»
Так что это дело разработчика (ваше дело!) — сообщить QNX/Neutrino, какие разделы программы следует выполнять параллельно. Проще всего это можно было бы сделать так:
>int main (int argc, char **argv) {
> int x1;
> ... // Выполнить инициализации
> for (x1 = 0; x1 < num_x_lines; x1++) {
> pthread_create(NULL, NULL, do_one_line, (void*)x1);
> }
> ... // Вывести результат
>}
С таким упрощением связано множество проблем. Первая из них (и самая незначительная) состоит в том, что функцию do_one_line() придется модифицировать так, чтобы она могла в качестве своего аргумента принимать значение типа >void*
вместо >int
. Это можно легко исправить с помощью оператора приведения типа (typecast).
Вторая проблема несколько сложнее. Скажем, что разрешающая способность дисплея, для которой вы рассчитывали картинку, была равна 1280×1024. Нам пришлось бы создать 1280 потоков! В общем-то, для QNX/Neutrino это не проблема — QNX/Neutrino позволяет создавать до 32767 потоков в одном процессе! Однако, каждый поток должен иметь свой уникальный стек. Если ваш стек имеет разумный размер (скажем 8 Кб), эта программа израсходует под стек 1280×8 Кб (10 мегабайт!) ОЗУ. И ради чего? В вашей системе есть только 4 процессора. Это означает, что только 4 из этих 1280 потоков будут работать одновременно, а другие 1276 потоков будут ожидать доступа к процессору. (В действительности, в данном случае пространство под стек будет выделяться только по мере необходимости. Но тем не менее, это все равно расходование ресурсов впустую — есть ведь еще и другие издержки.)
Более красивым способом решения этой задачи было бы разбить ее на 4 части (по одной подзадаче на каждый процессор), и обрабатывать каждую часть как отдельный поток: