NIF для переноса моего многопоточного кода C++

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

1. Запускается ли NIF в том же процессе ОС, что и остальные мои процессы erlang, или NIF запускается в отдельном процессе ОС?

2. Имеет ли смысл деформировать этот многопоточный код C++ с отслеживанием состояния с помощью NIF?

4. Если NIF не является правильным подходом, как мне лучше заставить Elrang говорить туда-сюда с этим кодом C++? Я также предпочитаю, чтобы мой код C++ находился внутри того же процесса ОС, что и остальные мои процессы Erlang, и, похоже, связанные драйверы являются опцией, но не уверен, что многопоточная природа моего кода C++ подойдет для этого. модель. Кроме того, я слышал, что они могут испортить планировщик elrang?


person iCode    schedule 25.09.2012    source источник


Ответы (1)


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

  2. Это зависит от функциональности, которую вы реализуете с помощью этого кода C++. Из-за ответа 1) вы, вероятно, захотите избежать параллелизма в части C++, поскольку это потенциальный источник ошибок. Конечно, это не всегда возможно. Но если вы реализуете, скажем, какой-то пул рабочих процессов, продолжайте реализовывать однопоточный код, порождая его столько раз, сколько вам нужно.

  3. Драйверы также могут быть многопоточными, с теми же потенциальными проблемами и довольно похожей производительностью (ну, все же немного быстрее, чем NIF). Если вы не совсем уверены в стабильности своего кода на C++, используйте его как порт на Erlang.

Говоря о разнице между NIF и драйверами, первый изначально синхронен, а второй может быть асинхронным (что может быть действительно огромным преимуществом, если вы не хотите получать какие-либо ответы на большинство команд). Драйверы легче испортить и сложнее реализовать (но как только вы поймете основные закономерности и проблемы, на самом деле они кажутся нормальными).

Вот хорошее начало для водителей: http://www.erlang.org/doc/apps/erts/driver.html

И что-то подобное (посмотрите на разницу в сложности) для NIF: http://www.erlang.org/doc/tutorial/nif.html

person demeshchuk    schedule 25.09.2012
comment
Спасибо за ответ. Дело в том, что я не могу изменить код C++, и он внутри создает некоторые ограниченные потоки. Кроме того, он имеет блокировки над некоторыми своими внутренними структурами данных, к которым вызовы nif могут получить доступ, и поэтому вызов nif может блокироваться до тех пор, пока внутренний поток не освободит блокировку. Это все еще нормально, если предположить, что код С++ не содержит ошибок? Кроме того, мне кажется, что все процессы Erlang выполняются только в одном потоке (у меня только одно ядро), а виртуальная машина не использует какой-либо пул потоков? Это правильно? Если да, то как нам добиться параллелизма в Erlang, поскольку мы никогда не знаем, сколько времени может занять каждый процесс erlang? - person iCode; 26.09.2012
comment
Если вы хотите получить асинхронное поведение, о котором вы говорите, вы должны использовать erlang.org/ doc/man/erl_nif.html#enif_thread_create для создания потока, в котором вы затем выполняете свой код C++. Вы используете канал или что-то подобное для связи с этим потоком и используете enif_send_term для отправки результатов. Внедрение драйвера может подойти вам лучше, поскольку тогда вы сможете использовать встроенный пул асинхронных потоков erlang для выполнения операций C++. Драйверы также имеют тенденцию быть более гибкими при работе в эмуляторе без smp (не то же самое, что smp: 1: 1). - person Lukas; 26.09.2012
comment
Количество потоков в Erlang не сильно влияет на параллелизм. Планировщик VM просто загружает процессорное время между всеми процессами (в соответствии с их приоритетом, который является нормальным по умолчанию и который вы можете установить для каждого процесса явно). Вы можете получить лучшее представление о том, что такое процессы Erlang, отсюда: c2.com/cgi/wiki?GreenVsNativeThreads< /а> - person demeshchuk; 26.09.2012
comment
Обычно вам не разрешено блокировать или ждать во время вызовов NIF, но в Erlang R17 представлены планировщики грязных операций ввода-вывода, которые позволяют это делать. Короче говоря, виртуальная машина будет запускать ваш NIF в отдельном потоке, чтобы потоки планировщика не пострадали от вашей блокировки/ожидания. - person goertzenator; 13.08.2014