Как портировать приложение с windows на linux

Мария Сысойкина

Проблема миграции

Наверное, уже ни для кого не секрет, что Linux в последние год-два все более уверенно занимает положение операционной системы для настольных компьютеров. Этому способствуют несколько факторов, и прежде всего – развитие самой ОС, совершенствование графических оболочек и оконных менеджеров. К примеру, последняя версия популярной графической среды KDE 3.1 ничем не уступает графическому интерфейсу Windows, а по возможностям настройки и наличию качественных приложений во многом превосходит его. Далее, немаловажный для России фактор – хорошая локализация ряда зарубежных дистрибутивов Linux и поддержка в них многочисленных кодировок кириллицы, а также появление и развитие высококачественных отечественных дистрибутивов (ASPLinux, ALTLinux). Еще один существенный фактор, правда, пока еще не вышедший на передний план в России – бесплатность Linux (или по крайней мере относительно невысокая стоимость: пользователь платит только за техническую поддержку, но не за само ПО).

На технических, технологических и прочих чисто программных достоинствах Linux останавливаться не будем, отметим лишь, что их достаточно, чтобы эта ОС составила достойную конкуренцию Windows.

Переход на Linux в рамках целой компании или организации – это прежде всего
решение, определяющее корпоративный стандарт. И каковы бы ни были преимущества
использования открытого ПО, в такой ситуации необходимо учитывать и потенциальные
сопутствующие сложности. А их может быть множество. Одна из них – это наличие
приложений, уже используемых в работе, необходимость обеспечить совместимость
с используемыми форматами данных, да и просто качество и удобство использования
этих приложений. В общем случае при переходе с одной платформы на другую можно
выделить несколько этапов (причем вполне вероятно, что все они окажутся актуальными):

  1. Использование в работе на новой ОС существующих «родных» для нее аналогов
    привычных приложений.
  2. Использование эмуляторов для запуска на новой ОС приложений из старой.
  3. Работа с уже портированными идентичными приложениями или с приложениями,
    разработанными параллельно для двух систем.
  4. Самостоятельный перенос собственных разработок в среду новой ОС.

Рассмотрим варианты этих схем применительно к переходу на Linux.

Использование Linux-приложений

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

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

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

Эмуляторы

Если говорить об эмуляции Windows-приложений в Linux или же о загрузке всей ОС Windows в среде Linux, вполне логично задаться вопросом – а какой в этой затее смысл, если мы переходим на Linux только для того, чтобы не работать в Windows?

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

Существует ряд пакетов, позволяющих создавать виртуальные машины – запускать в Linux уже установленную ранее на компьютере ОС Windows. Рассматривая вариант полного перехода компании или предприятия на использование Linux, я в такой эмуляции особого смысла не вижу. Во-первых, за использование Windows все равно придется платить, во-вторых, вряд ли служба техподдержки будет разбираться с тем, почему Windows не работает «из-под Linux». Да и вообще, к чему столько сложностей? Вариант сосуществования Windows и Linux оправдан в одном случае – когда вам приходится одновременно работать с обеими системами. Но если вы все-таки полностью переходите на Linux, то вряд ли вам понадобится эмулировать Windows целиком. Диски, отформатированные под FAT и NTFS, прекрасно «видны» и в Linux, протоколы работы с сетями Microsoft в Linux также имеются, а чтобы перенести в Linux нужную информацию со старой системы, вам вряд ли что-либо еще понадобится. И тем не менее рассказать обо всех возможностях эмуляции стоит.

Итак, существуют два способа работы Windows-приложений в Linux. Первый – это запуск отдельных приложений в XWindow, а второй – создание виртуальных машин для эмуляции выполнения в Linux ранее установленной на компьютере ОС Windows.

Запуск Windows-приложений в XWindow

Из существующих на сегодня средств запуска в Linux Windows-приложений можно
отметить библиотеки Wine и WineX, а также сравнительно недавнюю разработку Crossover
Office компании CodeWeavers (http://www.codeweavers.com).

Начну с самой известной программы, Wine. Расшифровывается ее название как Wine Is Not Emulator (Wine – это не эмулятор). Данный рекурсивный акроним справедлив: Wine и в самом деле не эмулятор. Это средство реализует некий промежуточный уровень совместимости приложений – функционирование Win32 и Win16 API на базе XWindow и Unix/Linux.

В состав Wine входят библиотеки разработчика (Winelib), предназначенные для переноса Windows-приложений в Linux, а также загрузчик программ, позволяющий многим исходным приложениям Windows 3.x/9x/NT/2000/XP выполняться на Unix-платформах, включая Linux и FreeBSD.

Wine не создает виртуальных машин, а поэтому не требует наличия самой Windows.
На программном уровне этот инструмент представляет собой полностью альтернативный
код, не имеющий ничего унаследованного от Microsoft. Однако при необходимости
он может использовать в работе доступные библиотеки Windows DLL. Wine распространяется
как продукт Open Source. Его новейшие версии можно найти по адресу http://www.winehq.org.

Вы можете установить и использовать Wine как при наличии на компьютере Windows, так и без этой системы. В любом случае сначала придется установить сам пакет Wine, затем правильно настроить его конфигурационный файл и только после этого пытаться либо запустить приложения уже имеющейся Windows (предварительно смонтировав соответствующий раздел), либо устанавливать Windows-приложения поверх «чистой» Linux.

Fig.1 Рис. 1. Windows-приложения, запущенные с помощью Wine.


WineX – это коммерческая версия Wine, разрабатываемая компанией Transgaming
(http://www.transgaming.com). Она ориентирована
прежде всего на работу Windows-игр в Linux, а следовательно, на поддержку технологии
DirectX.

Более серьезная и функциональная коммерческая версия Wine – пакет Crossover Office, изначально предназначавшийся для запуска в Linux офисных приложений Microsoft. Однако сейчас с помощью этого пакета в Linux можно работать со многими различными приложениями Windows.

Схема работы с Crossover Office такая же, как и с Wine. Сначала устанавливается и настраивается сам пакет, а затем устанавливаются необходимые Windows-программы. Однако для нормальной работы с офисными приложениями перед установкой Microsoft Office придется сначала найти и установить в системе необходимые шрифты в формате TTF.

После установки Windows-приложений в меню вашей графической оболочки появится раздел Programs, содержащий ссылки на установленные программы. В Crossover Office наряду с офисным пакетом запускаются и такие общеизвестные приложения, как Windows Multimedia Player, Adobe Photoshop, WinAmp, PageMaker и т. д.

Создание виртуальных машин

Виртуальный компьютер – специальная программа, имитирующая для других программ
инородный физический компьютер. Пожалуй, самое выдающееся средство создания
виртуальных машин – это пакет VMWare. В качестве монитора виртуального компьютера
в Linux здесь используется окно графической оболочки X XWindow. Виртуальный
компьютер «строится» из следующего набора виртуальных устройств:

  • виртуальные жесткие диски IDE и SCSI, виртуальный дисковод CD-ROM;
  • стандартный дисковод гибких дисков;
  • контроллер жестких IDE-дисков Intel 82371 PCI Bus Master, поддерживающий
    два первичных (primary) и два вторичных (secondary) IDE-диска;
  • адаптер SCSI-дисков, совместимый с BusLogic BT-958;
  • стандартный графический PCI-адаптер, стандартная 101/102-клавишная клавиатура,
    PS/2-совместимая мышь;
  • сетевая плата AMD PCNET Family Ethernet adapter (PCI-ISA);
  • последовательные порты COM1 – COM4, параллельные порты LPT1, LPT2;
  • звуковая плата, совместимая с Sound Blaster 16.

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

Однако при запущенной виртуальной машине на компьютере реально работают две ОС, и соответственно обе они одновременно занимают какое-то количество ресурсов. Именно поэтому VMWare предъявляет достаточно высокие требования к конфигурации компьютера (физического, а не виртуальной машины). Чем мощнее базовый компьютер, тем менее заметна разница в быстродействии реальной и виртуальной ОС.

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

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

После всех установок вы сможете «включить» виртуальный компьютер и запустить вторую ОС одновременно с уже работающей базовой ОС Linux, под управлением которой продолжает работать физический компьютер.

Еще один, более простой механизм «виртуальных машин» – это программа Win4Lin. Она проще, чем VMWare, поскольку создавалась и оптимизировалась именно для работы с Windows в Linux. Такая специализация повысила надежность и быстродействие, снизив требования к ресурсам компьютера. Единственное «но» заключается в том, что помимо самого дистрибутива вам придется установить еще одно ядро (нужно будет выбрать именно такое, на каком в данный момент работает Linux.). В результате в системе будет два ядра, а в загрузчике lilo появится дополнительная опция, позволяющая загружать Linux именно с ядром, поддерживающим эмулятор.

После установки нужно будет опять-таки установить Windows и приложения. Число доступных приложений при этом достаточно велико. На сайте Win4Lin представлен лишь небольшой список, включающий такие приложения, как Microsoft Office, Internet Explorer, продукты Macromedia и Adobe.

Fig.2 Рис. 2. Win4Lin и Windows-приложения в Linux.


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

Что же делать, если переходить на Linux все-таки необходимо? Можно отложить в сторону «родные» Linux-приложения и эмуляторы и попытаться найти нужное ПО среди уже перенесенных на платформу Linux приложений.

Портирование приложений

В числе серьезных общеизвестных продуктов, имеющих свои Linux-версии, сегодня можно назвать СУБД Oracle, Interbase (Linux-версия называется FireBird), IBM DB2, а также пакеты Lotus Domino, Netscape, Adobe Acrobat, средство разработки Borland Kylix (Delphi и C++ для Linux) и т. д. Однако следует учесть, что многие из портированных приложений вовсе не бесплатны и не распространяются по лицензии GNU GPL.

Существует ряд популярных Windows-приложений, изначально создававшихся под Linux, в частности, Web-сервер Apache, браузер Mozilla, средство для работы с графикой Gimp. Тем не менее вполне возможно, что вы не найдете Linux-версии нужного вам приложения. Проблема состоит в том, что подавляющее большинство ПО для Windows – закрытые коммерческие проекты. Следовательно, правами на исходные тексты и их изменение владеют сами разработчики, и только они сами могут заниматься переносом приложения на другую платформу. В этом отношении ситуация с обратным переносом, из Linux в Windows, обстоит намного проще – приложения для Linux в массе своей распространяются по лицензии GPL с открытыми исходными кодами. Таким образом, рано или поздно находятся энтузиасты, компилирующие эти коды под Windows. К примеру, именно так на свет появился пакет Gimp для Windows – мощный бесплатный редактор растровой графики.

Но далеко не все компании-разработчики готовы создавать Linux-версии своих продуктов. Многое определяется сложностью переноса и его обоснованностью – окупятся ли затраты на портирование приложения в ходе его дальнейшего распространения? Сейчас ситуация напоминает замкнутый круг. Пользователи Linux испытывают недостаток нужного ПО, поэтому Linux развивается как персональная ОС не так активно, как хотелось бы. А разработчики этого ПО сомневаются в необходимости переноса приложений на Linux, потому что пользователей Linux-версий пока не так много.

Можно предположить, что скорее всего портированное приложение не будет бесплатным и открытым. Случаи распространения Linux-версий коммерческих приложений по лицензии GNU/GPL автору неизвестны.

Помимо «политических» вопросов, перед разработчиками встает ряд проблем технического характера. Сложность переноса каждого конкретного приложения зависит не только от его масштаба и количества затраченных человеко-часов, но прежде всего от того, насколько грамотно оно изначально написано. Если приложение тесно взаимодействует непосредственно с API Windows, использует различные системные вызовы, обращается к динамическим библиотекам и т. п., то сложности при переносе гарантированы. Кроме того, если приложение, например, взаимодействует с СУБД и сервером БД, то не факт, что аналогичные средства существуют в Linux. В этом случае придется заниматься еще и переделкой приложения под новое ядро БД.

Если же портируется приложение, написанное на чистом C/C++ или Java, то количество возникающих проблем сводится к минимуму. Останется переписать только те фрагменты приложений, где явно задействованы платформно-зависимые моменты – например, пути к файлам (в Linux отсутствует понятие диска, расширения файлов, различается регистр в именах файлов) или обращения к конфигурации системы (в Linux нет системного реестра, вместо него используются конфигурационные файлы и сценарии). Так что даже если приложение изначально было написано с минимальной зависимостью от Windows API, все равно «приятных мелочей» при переносе возникает немало, и отслеживание всех подобных моментов вручную – довольно долгое и сложное дело.

На этот случай существуют дополнительные средства поддержки миграции – приложения или пакеты, позволяющие при написании кода отслеживать фрагменты, зависящие от платформы. Пример такого пакета – Visual MainWin, созданная компанией MainSoft надстройка для Microsoft Visual Studio.

Visual MainWin – это полностью кросс-платформенное решение, значительно упрощающее разработку и внедрение приложений на платформах Linux и Unix, создаваемых в среде Microsoft Visual Studio. Кроме того, Visual MainWin содержит пакет интеграции с J2EE и полную поддержку XML.

В состав Visual MainWin 5 входят инструментарий SDK для разработки приложений и пакет Visual MainWin Runtime для внедрения приложений. Инструментарий Visual MainWin SDK встраивается в визуальную среду разработки Visual Studio. Он дополняет существующие в Visual Studio конфигурации сборки приложений, добавляя в список несколько Unix-платформ. При сборке приложения используется технология Remote Development Technology, которая разбивает этот процесс на отдельные операции (компиляция, компоновка и т. д.) и удаленно выполняет их на платформах Unix с использованием «родных» компиляторов C++ для Unix.

Fig.3 Рис. 3. Компиляция приложения с использованием Visual MainWin.


Результаты такой сборки отображаются в среде Visual Studio, как и при работе с кодом, собираемым на локальной машине. При этом расширенный компилятор самостоятельно разрешает и исправляет несоответствия в синтаксисе исходных кодов и различия между компиляторами Microsoft Visual C++ и Unix C++.

Пакет Visual MainWin Runtime состоит из модуля Windows Runtime для Unix и базовых сервисов (Visual MainWin Core Services). Вместе они позволяют выполнять Windows-приложения в среде Unix. По утверждениям представителей MainSoft, приложения, перенос которых в обычных условиях занимает около полутора лет, с использованием Visual MainWin будут портированы на Linux в течение полугода.

Средства, облегчающие перенос приложений в Linux, существуют и для разработок, создаваемых в среде Delphi и Borland С++. В первую очередь здесь, конечно же, следует упомянуть пакет Borland Kylix, последняя версия которого объединяет в рамках одного проекта две интегрированные среды разработки – Delphi и C++ для Linux.

Приложения, созданные в Delphi для Windows, достаточно легко переносятся на Linux (при условии, что при разработке приложения не были задействованы напрямую вызовы Windows API). При этом немаловажную роль играет и то, что в Linux приложение будет компилироваться в практически идентичной среде (Kylix – полный аналог Delphi и по интерфейсу IDE, и по возможностям). Кроме того, и Delphi, и Kylix поддерживают одинаковый набор кросс-платформенных компонентов, из которых строится приложение. Компоненты эти написаны без использования Windows API. Вместо этого в их основу положены кросс-платформенные библиотеки Qt производства TrollTech.

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

Этот подход реализован в продуктах Borland – Kylix и Delphi. Вы можете использовать один и тот же исходный код, но компилировать его для Windows в Delphi, а для Linux – в Kylix. При этом в библиотеках обеих сред заложены различные функции и константы, обеспечивающие легкость разработки. Например, чтобы не переписывать несколько раз участок кода, в котором происходит обращение к файлам, но при этом учесть особенности каждой системы (прямой слэш или обратный, буква, обозначающая диск, и т. д.), можно воспользоваться соответствующими константами – PathDelim, DriveDelim и PathSep. Далее компилятор сам подставит нужное значение в зависимости от того, для какой ОС компилируется код.

Если среда не позволяет обобщить код для обеих платформ, можно выделить отдельные участки кода, используя директивы компилятора [$IFDEF MSWINDOWS] и [$IFDEF LINUX]. В этом случае компилятор сам выберет, какой участок кода компилировать, а какой пропустить.

Еще одно средство кросс-платформенной разработки – уже упоминавшиеся библиотеки Qt и Qt API (инструментарий для создания приложений). Версии этих библиотек есть как для Windows, так и для Linux.

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

Tutorials > Porting > Porting a Windows App to Linux with Visual Studio

This tutorial shows how to port a simple Windows application to Linux by creating a Linux configuration in a Visual Studio project with VisualGDB.

Before we begin, ensure that VisualGDB 4.0 or later is installed.

  1. Our first step will be to create a simple console application for Windows. Start Visual Studio and select File->New->Project. 01-newproj
  2.  Select “Win32 Console Application”:02-consoleapp
  3. Proceed with the default settings and press “Finish”. Visual Studio will create a basic console application. Add the following code to the main file:

    #include «stdafx.h»

    #include <stdio.h>

    #include <stdlib.h>

    int _tmain(int argc, _TCHAR* argv[])

    {

        printf(«HOMEPATH=%s\n», getenv(«HOMEPATH»));

        printf(«HOME=%s\n», getenv(«HOME»));

        return 0;

    }

  4. Build the project. If the build complains about the getenv() function, add the following line to the beginning of stdafx.h:

    #define _CRT_SECURE_NO_WARNINGS

    Run the project and observe its output. Note that on Windows the HOME variable is undefined:03-sourcecode

  5. Now we will create a new Linux configuration for the project. Select Project->Add VisualGDB Configuration->New Linux Configuration:04-newcfg
  6. VisualGDB will start the Linux Configuration Wizard. Enter “LinuxDebug” as the configuration name:05-summary
  7. On the next page select the Linux computer you want to use. You can also select a different toolchain:06-linuxcomp
  8. The last page allows specifying the location of the source files on the Linux machine. You can proceed with the default settings:07-sourcelocation
  9. When you press Finish, VisualGDB will create a new project configuration and a corresponding solution configuration. As certain Windows-specific files are missing on the Linux machine, the compilation will fail with several errors. We will fix them in the next steps:12-errors
  10. Open the stdafx.h file and remove references to SDKDDKVer.h and tchar.h:13-linux
  11. Rename _tmain() to main() and replace _TCHAR with char. Build the project. You will notice that the modified source files will be transferred to the Linux machine and built there using GCC, the standard compiler on Linux systems:14-buildok
  12. Set a breakpoint on the return statement and run the program. Observe the output:15-debug
  13. As Windows and Linux use different variable names (HOMEPATH vs HOME), we had to write two separate getenv() lines. Now we will add conditional compilation statements to ensure that only one line is used on each OS. We could test for the _MSC_VER macro on Windows (that is set by the Visual C++ compiler) or the LINUX macro that is defined by Linux headers, however in this tutorial we will show how to add your own macro. Right-click on the project, select VisualGDB Project Properties and go to the Makefile Settings page. Add BUILDING_FOR_LINUX to Preprocessor Macros:16-macro
  14. Now press OK and add the #ifndef BUILDING_FOR_LINUX statement to your code. Build and run the program. Observe that the output only contains one line now:17-ifdef
  15. Now switch the current configuration back to Debug and hit F5 to run the Windows version of your program:18-windows
  16. As most of the API (except for the basic standard functions) is different between Linux and Windows, you may want avoid having too many #ifdef statements and simplify your porting. You can accomplish this in one of the following ways:
    • Use a multi-platform framework like QT that abstracts out the differences between platforms
    • Install Cygwin and create a Cygwin configuration via Project->Add VisualGDB Configuration->Windows. Cygwin provides equivalents to most Linux APIs on Windows so once you have ported your app to Linux you can build the Windows version of it without too many changes.

If you are using Windows 10, you can also use the Windows Subsystem for Linux to build, debug and test your Linux code. See this tutorial for a detailed description.

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

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


0

2

Имется рабочий проект (cpp)винду. Необходимо перенести на его Linux и продолжить программировать далее. С Линуксом работал на уровне пользователя (знаком с командной строкой). Проект написан Microsoft Visual Studio 2010. Учитывая вышеизложенное, прошу помочь советом
— на какой платформе/системе лучше всего начать?
— какие пакеты С++ необходимы для старта/переноса исходников?
— где брать стандартные библиотеки?
— что нужно еще?
Спасибо.

  • Ссылка

Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.

Время на прочтение
8 мин

Количество просмотров 8.3K

image

Введение

Однажды перед нами была поставлена задача: портировать набор приложений на C# с Windows/.NET Framework на Linux/.NET Core. Я полагаю, что для Microsoft мы были клиентом с рабочими нагрузками, которые было бы интересно поддерживать с помощью .NET Core. В то время я не понимал, насколько сильным было их стремление работать с нами. Наш подход к Open Source был решающим фактором.

Насколько сложной она может быть? Ну… в этом посте мы расскажем вам о трудностях, с которыми нам пришлось столкнуться, чтобы запускать, контролировать и отлаживать наши приложения.

Попробуйте

Как только мы получили билд всех сборок .NET Core (подробнее об этом в одной из следующих статей блога), пришло время запустить несколько приложений. Первые проблемы, с которыми мы столкнулись, были связаны с отсутствием функций между .NET Framework и .NET Core. Например, нам нужна поддержка криптографии 3DES и AES с режимом шифрования CFB, но она (все еще) отсутствует в .NET Core для Linux. Благодаря статусу Open Source .NET Core мы смогли добавить ее в CoreFx. Однако, поскольку мы не реализовали его на MacOS/Windows, как того требовала Microsoft, чтобы наше изменение было принято в качестве Pull Request, нам пришлось сохранить нашу форкнутую ветку.

Второй класс проблем рантайма, которые нам пришлось решать, был связан с различиями между Windows и Linux, а также с «контейнеризацией» рантайма. Рассмотрим два примера, связанных со сборщиком мусора .NET. Во-первых, наши контейнеры использовали Linux cgroups для управления квотами, включая память и количество ядер процессора, используемых приложениями. Однако при запуске CLR GC подсчитывал общее количество ядер CPU, чтобы вычислить количество куч для выделения, а не то, которое определено на уровне cgroup: В итоге мы получали мгновенное автоматическое уничтожение Out Of Memory. На этот раз наше исправление было сделано и внесено в репозиторий CLR.

Второй пример связан с оптимизацией GC: Во время фоновой сборки мусора 2-го поколения потоки CLR, работающие под ними, аффинируются к каждому отдельному ядру CPU, чтобы избежать блокировок. Нам посчастливилось принять Маони Стивенс (ведущего разработчика GC) в нашем парижском офисе в начале 2018 года, чтобы поделиться нашими странными паттернами распределения, которые влияют на GC. Во время своего пребывания она была достаточно любезна, чтобы помочь нам исследовать поведение на наших серверах: Когда был запущен SysInternals ProcessExplorer, сборка мусора занимала больше времени, чем обычно. Маони обнаружила, что ProcessExplorer имеет аффинитизированный поток с высоким приоритетом, конфликтующий с потоками GC. Во время расследования, связанного с более длительным временем отклика в Linux по сравнению с Windows. Мы поняли, что потоки GC не были аффинитизированы, как это было в случае с Windows, и проблема была исправлена Яном Ворличеком.

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

Контролируйте его

Наши приборные панели Grafana, измеряющие состояние приложений .NET Framework, были основаны на метриках, вычисленных на основе счетчиков производительности Windows. Даже без перехода на Linux, .NET Core больше не предоставляет счетчики производительности, поэтому нам пришлось полностью перестроить нашу систему сбора метрик!

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

Наша первая реализация сбора метрик в Linux была основана на LTTng, и мы представили наш путь во время Tracing Summit в 2017 году. Microsoft уже создала TraceEvent, сборку, позволяющую коду .NET анализировать события CLR как для Windows, так и для Linux. К сожалению для нас, Linux-часть могла только загружать файлы трассировки, но нам нужна была живая сессия, как в Windows, где можно слушать события, испускаемые запущенными приложениями. Поскольку этот код является Open Source, Грегори смог добавить функцию живой сессии в TraceEvent.

В .NET Core 3.0 Microsoft предоставила способ обмена событиями, общий для Linux и Windows, под названием EventPipes. Итак… мы перенесли нашу реализацию коллекции с LTTng на EventPipe (смотрите серию наших блогов и сессию конференции DotNext для получения более подробной информации и примера многократно используемого кода). С новой реализацией EventPipe в CLR возникли проблемы с производительностью, не замеченные Microsoft. Причина проста: Некоторые из наших приложений запускают сотни потоков для обработки тысяч запросов в секунду и выделяют память как сумасшедшие. В таком контексте CLR нужно многое сделать, а значит, нужно генерировать и передавать много событий через LTTng или EventPipes.

image

(Количество обработанных событий CLR в минуту; даже при ограниченном количестве ключевых слов gc/thread/exception, которые мы используем, выдается еще больше)

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

Microsoft не «просто» перешла на Open Source, команды работают в глубокой интеграции с моделью выпуска/запроса на GitHub. Поэтому не стесняйтесь и, если вы обнаружили проблему, создайте задачу с подробным описанием, а еще лучше — предоставьте запрос на исправление. От этого выиграет все сообщество!

Запускайте

С помощью этих показателей мы начали исследовать некоторые различия в производительности (в основном время отклика) между Windows и контейнерным Linux.

image

(Чем ниже, тем лучше)

Мы увидели огромную разницу в производительности на Linux: Как время отклика (x2), так и масштабируемость (увеличение таймаута с ростом QPS). Наша команда потратила много времени на улучшение ситуации, вплоть до того, что можно было отправлять приложения в продакшн.

В новой среде с контейнерами мы столкнулись с теми же признаками шумных соседей, что и в Process Explorer. Если ядра процессора не выделены для контейнера (как это было у нас в начале), такой сценарий происходит очень часто. Поэтому мы обновили систему планирования, чтобы выделить ядра ЦП для контейнеров.

В совершенно другой области мы обнаружили, что то, как .NET Core обрабатывает сетевой ввод-вывод, повлияло на наше основное приложение. Чтобы немного пояснить, это приложение должно обрабатывать большое количество запросов и зависит от времени отклика. Во время обработки запроса текущему потоку может потребоваться отправить HTTP-запрос, прежде чем продолжить обработку. Поскольку это делается асинхронно, поток становится доступным для обработки большего количества входящих запросов, что хорошо для пропускной способности. Однако это означает, что когда внутренний HTTP-запрос вернется, все доступные потоки могут обрабатывать новые входящие запросы, и потребуется время для завершения старого. Чистый эффект — увеличение медианного времени отклика, а это не то, чего мы хотим!

Реализация .NET Core полагается на .NET ThreadPool, который разделяет свои потоки со всей магией async/await и обработкой входящих запросов (реализация .NET Framework использует совершенно другую реализацию, основанную на портах завершения ввода/вывода в Windows). Чтобы решить эту проблему, Кевин реализовал собственный пул потоков для обработки сетевого ввода-вывода, и мы продолжаем его оптимизировать. Когда вы работаете над такой глубокой областью кода, разделяемой столькими различными рабочими нагрузками, вы понимаете, что невозможно найти «серебряную пулю».

Отладка

Что бы вы сделали, если бы что-то пошло не так в приложении? В Windows с помощью Visual Studio мы можем удаленно отлаживать неавторизованное приложение, чтобы установить точку останова, просмотреть поля и свойства или даже получить высокоуровневое представление о том, что делают потоки с помощью представления ParallelStacks. В худшем случае SysInternals procdump позволяет нам сделать снимок приложения и проанализировать его на машине разработчика с помощью WinDBG или Visual Studio.

Что касается удаленной отладки приложения Linux, Microsoft предоставляет решение на основе SSH для подключения к запущенному приложению. Однако, по соображениям безопасности, в наших контейнерах нельзя запускать SSH-сервер. Решением было реализовать протокол связи с VsDbg для Linux поверх WebSockets.

image

Приложение Remote Debugger sidecar на рисунке проксирует команды из Visual Studio в VsDbg, который действует как отладчик Linux .NET с приложением. Нет необходимости в рискованном SSH, только аккуратный HTTP.

Ну… этого оказалось недостаточно. Архитектура хостинга (Marathon и Mesos в нашем случае) обеспечивает бесперебойную работу приложений в контейнерах, отправляя запросы на конечные точки проверки работоспособности. Если приложение отвечает, что все в порядке, значит, контейнер в безопасности. Если приложение не отвечает, как ожидалось (включая повторные попытки), то Marathon/Mesos убивает приложение и очищает контейнер. Теперь подумайте, что произойдет, если вы установите точку останова в приложении и несколько минут будете копаться в содержимом структур данных в панелях Visual Studio Watch/Quick Watch. За сценой отладчик должен заморозить все потоки приложения, включая те из пула потоков, которые отвечают за проверку работоспособности. Как вы уже, наверное, догадались, сеанс отладки ничем хорошим не закончится.

Именно поэтому на предыдущем рисунке показана стрелка между Marathon и удаленным отладчиком, который действует как прокси для проверки работоспособности приложения. Когда начинается сеанс отладки (т.е. когда код WebSockets выполняет протокол), удаленный отладчик знает, что ему следует ответить OK вместо вызова конечной точки приложения, которая может никогда не ответить.

Когда удаленной отладки недостаточно, как сделать моментальный снимок памяти приложения? Например, если проверка работоспособности не отвечает после серии повторных попыток, удаленный отладчик вызывает инструмент createdump, установленный вместе со средой выполнения .NET Core, для создания файла дампа. Опять же, поскольку создание дампа памяти приложения размером 40+ ГБ может занять несколько минут, был введен тот же механизм прокси проверки работоспособности.

Как только файл дампа будет создан, удаленный отладчик позволит Marathon уничтожить приложение. Но подождите! Этого недостаточно, потому что в этом случае контейнер будет очищен, а дисковое хранилище исчезнет. Это не проблема, после создания дампа программой createdump, файл отправляется в приложение «Dump Navigator» (по одному на центр обработки данных). Это приложение предоставляет простой пользовательский интерфейс HTML для получения высокоуровневых деталей состояния приложения, таких как стеки потоков или содержимое управляемой кучи.

image

В Windows мы создали собственный набор команд расширения, которые позволяют нам исследовать память, нехватку пула потоков, конкуренцию потоков или случаи утечки таймера в дампе памяти Windows с помощью WinDBG, как показано на этой сессии конференции NDC Oslo. Обратите внимание, что их также можно использовать с LLDB в Linux. Эти команды используют библиотеку ClrMD Microsoft, которая дает вам доступ к реальному процессу или дампу памяти в C#. Благодаря поддержке Linux, которая была добавлена в эту библиотеку разработчиками Microsoft, код было легко повторно использовать в нашем приложении Dump Navigator. Я однозначно рекомендую обратить внимание на API, предоставляемый ClrMD, для автоматизации и создания собственных инструментов.

Заключение

Несмотря на то, что некоторые из наших основных приложений перешли на .NET Core, работающий на контейнерном Linux с большим набором инструментов мониторинга/отладки, путь еще не закончен. Сейчас мы тестируем предварительную версию .NET Core 5.0 (как мы это делали для 3.0). Если это не так, мы выясним причины и найдем решения для интеграции в код. То же самое касается инструментов: я начал добавлять наши команды расширения в инструмент Microsoft dotnet-dump CLI, используемый для анализа дампов Windows и Linux.

По крайней мере, мы можем сказать, что помогли не только себе, но и Microsoft понять, как далеко может зайти .NET Core, и даже всему сообществу .NET Windows и Linux. Вот где Open Source сияет!

  • Как после переустановки windows не переустанавливать игры
  • Как после переустановки windows настроить принтер
  • Как после переустановки windows 7 настроить wifi на ноутбуке windows
  • Как послать udp пакет windows
  • Как портировать android приложение на windows