Перенос программ на C++ из Windows в Linux: работаем с потоками

26/06/23
Технические статьи
Перенос программ на C++ из Windows в Linux: работаем с потоками

Перенос программ на C++ с Windows на Linux включает в себя ряд особенностей, связанных с работой с потоками. Эта тема актуальна для разработчиков, занимающихся портированием приложений с Windows на Linux. Перенос приложений между операционными системами может вызывать различные проблемы, связанные с особенностями работы каждой из них, включая способы управления потоками.

В данной статье мы рассмотрим основные различия между Windows и Linux в контексте работы с потоками, а также предоставим рекомендации по выбору библиотек в зависимости от задач вашего проекта. Эта информация будет полезна инженерам-разработчикам, столкнувшимся с потребностью мигрировать свои существующие приложения на операционную систему Linux. Миграция на Linux может быть необходима для обеспечения стабильности и непрерывной работы инфраструктуры компаний, особенно в ситуациях, когда становится сложнее продлить или приобрести новые лицензии, получить техническую поддержку от вендоров для критических обновлений и исправлений уязвимостей в системе.

Windows vs Linux: многозадачность и работа с потоками

Windows и Linux представляют собой две ведущие операционные системы, которые имеют свои особенности в отношении многозадачности и работы с потоками.

Типы многозадачности

Windows поддерживает два типа многозадачности: преемственную (preemptive multitasking) и кооперативную (cooperative multitasking). В преемственной многозадачности операционная система равномерно распределяет время процессора между потоками, переключая контексты выполнения. Это позволяет эффективно использовать ресурсы и предотвращать длительные блокировки потоков. С другой стороны, в кооперативной многозадачности каждый поток должен явно передавать управление другим потокам. Это требует взаимодействия и сотрудничества между потоками, но может привести к блокировке и сбоям системы, если какой-либо поток не выполняет передачу управления другим потокам.

Linux использует только преемственную многозадачность.

Процессы

В операционной системе Windows процессы более изолированы друг от друга благодаря использованию отдельных адресных пространств. Создание потоков в Windows осуществляется с помощью функции CreateThread, и каждый поток имеет собственный стек и уровень приоритета выполнения. Контроль над потоками осуществляется с помощью функций SuspendThread, ResumeThread и TerminateThread. Кроме того, в Windows существует понятие «фибров», которые являются легковесными потоками и используют стеки других потоков.

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

В Linux также существуют «процессы-потомки», которые создаются родительским процессом и имеют свои собственные адресные пространства. Это позволяет процессу-предку создавать и управлять отдельными процессами, которые могут выполнять свои задачи независимо друг от друга.

Кроссплатформенные библиотеки для работы с потоками

Обычно большинство библиотек для работы с потоками, специфичных для Windows и не поддерживаемых в ОС Linux, могут быть относительно легко перенесены с помощью кроссплатформенных библиотек. При переносе программы из Windows в Linux рекомендуется сначала выбрать подходящую кроссплатформенную библиотеку, перенести код на нее, а затем скомпилировать код для работы в Linux.

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

C++ Standard Thread Library — это библиотека, предоставляемая стандартом языка C. Она содержит классы для работы с потоками, такие как std::thread и std::async, а также множество других функций для синхронизации потоков, таких как std::mutex, std::lock_guard, std::condition_variable и другие. STL библиотека предоставляет переносимый и удобный интерфейс для работы с потоками в C++. Она интегрируется хорошо с другими компонентами языка, но имеет ограниченные возможности, не поддерживает некоторые специфические функциональности, и требует хорошего понимания многопоточности для безопасного использования. Для более сложных сценариев могут потребоваться дополнительные библиотеки или фреймворки.

Intel Threading Building Blocks является кроссплатформенной библиотекой для разработки приложений на C++, которая может использоваться для разработки приложений под различные операционные системы, в том числе Linux. TBB включает в себя классы и шаблоны для работы с потоками, такие как tbb::task_group, tbb::task_scheduler_init, tbb::parallel_for и другие, а также классы для синхронизации потоков, такие как tbb::spin_mutex и tbb::concurrent_queue. Эта библиотека хорошо зарекомендовала себя при переносе PPL (Parallel Patterns Library) библиотеки, разработанной компанией Microsoft для работы с многопоточностью на C++. PPL предоставляет простой и удобный интерфейс для создания параллельных алгоритмов и выполнения операций в многопоточной среде. Однако, PPL не является кроссплатформенным и не поддерживается ОС Linux. Работает быстро, оптимизирована под параллельные вычисления на процессорах Intel.

Qt — это кроссплатформенный фреймворк для разработки приложений на C++, который также предоставляет классы для работы с потоками. Qt включает в себя классы для создания и управления потоками, такие как QThread, QThreadPool и другие, а также классы для синхронизации потоков, такие как QMutex, QReadWriteLock и другие.

В наших проектах мы часто используем библиотеку Qt для переноса функциональности, основанной на MFC (Microsoft Foundation Classes) — классах, предоставляемых Microsoft для разработки Windows-приложений. MFC включает в себя классы для работы с потоками, такие как CWinThread и другие. Так как MFC не поддерживается в Linux, мы находим Qt полезной альтернативой, так как она предоставляет схожие классы для работы с потоками. Используя Qt, мы можем эффективно перенести и переиспользовать логику потоковых операций, разработанных с использованием MFC в Windows-приложениях, в Linux.

SDL (Simple DirectMedia Layer) — это кроссплатформенная библиотека, разработанная для создания мультимедийных приложений на C++. Она также предоставляет классы для работы с потоками, такие как SDL_Thread и другие, а также классы для синхронизации потоков, такие как SDL_mutex и другие. SDL рекомендуется для работы с мультимедийными функциями, такими как работа с изображениями, звуком и вводом.

Boost C++ Libraries — это кроссплатформенная библиотека для разработки приложений на C++, которая поддерживает различные операционные системы, включая Linux. Она включает в себя классы для работы с потоками, такие как boost::thread, boost::thread_group и другие, а также классы для синхронизации потоков, такие как boost::mutex и boost::lock_guard. Boost рекомендуется использовать в случаях, когда требуется перенос приложений, использующих ATL (Active Template Library) — набор классов Microsoft для разработки Windows-приложений. ATL также включает классы для работы с потоками, например, такие как CAtlExeModuleT, но не является кроссплатформенным и не поддерживается в Linux. Boost C++ Libraries предоставляет аналогичные классы для работы с потоками, например, boost::thread, который предоставляет интерфейс для создания потоков и выполнения операций в них.

OpenMP (Open Multi-Processing) — это кроссплатформенная библиотека, позволяющая создавать многопоточные приложения с использованием директив препроцессора. Она поддерживается на различных платформах, включая Linux, и предоставляет разнообразные директивы, такие как #pragma omp parallel, #pragma omp for, #pragma omp sections и другие. Библиотека особенно полезна в ситуациях, когда требуется обработка большого объема данных параллельно. Она позволяет эффективно использовать множество процессорных ядер и распределить нагрузку на выполнение задач между потоками, ускоряя общее время выполнения программы.

Библиотека libuv предоставляет возможности для создания многопоточных приложений на C++. Она поддерживается на различных платформах, включая Linux, и предоставляет простой и удобный API для работы с потоками. Одной из особенностей libuv является наличие встроенного пула потоков, который позволяет выполнять асинхронные операции с максимальной производительностью и эффективностью в многопоточной среде.

Для создания новых потоков в приложении в libuv используется класс uv_thread_t, аналогичный функции CreateThread в WinAPI и директиве #pragma omp parallel в OpenMP. В отличие от Windows Thread Pool API, предоставляемого Microsoft в операционной системе Windows, libuv является кроссплатформенной и поддерживается не только на Windows, но и на других операционных системах. Поэтому наши инженеры обнаружили, что libuv является наиболее удобным и эффективным средством для переноса кода, основанного на Windows Thread Pool API, на Linux или другие платформы.

Выводы

Перенос приложений с Windows на Linux с использованием кроссплатформенных библиотек является наиболее распространенным сценарием. Однако, иногда при разработке приложений были использованы специфичные для Windows библиотеки, и в таких случаях требуется проявить творческий подход, чтобы обеспечить производительность и совместимость приложений на новой платформе.

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

На данный момент для российских разработчиков и владельцев продуктов критическое значение имеет не только процесс переноса приложений на Linux, но и правильный выбор дистрибутива этой популярной операционной системы. Несмотря на свою «открытость», некоторые пользователи в России могут столкнуться с определенными сложностями при использовании конкретных дистрибутивов Linux.

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

Свяжитесь с нами напрямую

Офисы

Москва

117587, Варшавское ш., д. 125, стр. 16А

Ростов-на-Дону

344002, пр. Буденновский, д. 9, офис 305

Нижний Новгород

603104, ул. Нартова, д. 6, корп. 6, офис 829