Обратный P / Invoke (также) управляемый обратный вызов для неуправляемого кода - PullRequest
4 голосов
/ 07 января 2012

Включенный модульный тест C # и файл кода C пытаются передать управляемый обратный вызов неуправляемому коду. Код фактически выполняется, но переменная count никогда не увеличивается. Таким образом, тест не пройден.

Тот факт, что он выполняется вообще, означает, что он загружает dll, находит ссылку для метода DoCallBack () и, кажется, вызывает метод. Но ничего не происходит. Так что что-то не так.

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

По следующей ссылке вы найдете более быструю, на сегодняшний день, технику по кросс-производительности AppDomain. Команда MS .Net AddIn предлагает «FastPath», который значительно улучшает производительность удаленного взаимодействия. Мы запустили их пример на .Net 3.5, и он работает очень быстро после помещения их контрактов AddIn в GAC.

http://blogs.msdn.com/b/clraddins/archive/2008/02/22/add-in-performance-what-can-you-expect-as-you-cross-an-isolation-boundary-and-how-to-make-it-better-jesse-kaplan.aspx

Теперь давайте обсудим некоторые сопутствующие расчеты времени, чтобы понять, почему это все еще недостаточно быстро для наших нужд. Обычное междоменное удаленное взаимодействие предлагает примерно 10000 вызовов в секунду для метода с нулевыми аргументами. С опцией FastPath, которая увеличивается до 200 000 вызовов в секунду. Но, сравнивая это с C # вызова метода интерфейса с нулевыми аргументами (в том же домене), он выполняет более 160 000 000 операций в секунду на той же машине, что и другие тесты.

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

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

Но новым требованием к функции будет возможность предлагать архитектуру AddIn или Plugin, чтобы компоненты могли загружаться или выгружаться без остановки остальной системы. Единственный способ сделать это эффективно в .Net - использовать отдельные домены приложений.

Обратите внимание, что мы не хотим передавать данные через домены приложений, все они работают независимо друг от друга параллельно.

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

Итак, план здесь заключается в том, чтобы иметь основной или основной домен, который имеет пул потоков и по очереди вызывает каждый домен AppDomain, который нужно сделать, и позволяет ему работать некоторое время. Так что это означает совместную многопоточность (чтобы избежать переключения контекста). Поэтому домены приложений вернутся, чтобы основной домен приложений перешел к другим.

К сожалению, каждый AppDomain не может работать очень долго независимо до того, как закончится работа, и ему нужно вернуться в основной домен, чтобы позволить другому AppDomain работать ... так что время производительности 200 000 в секунду из-за техники FastPath приведет к значительное снижение общей производительности из-за кросс-доменных вызовов.

В отличие от PInvoke, приведенного ниже, мы измерили время с помощью StopWatch, чтобы производить более 90 000 000 - это 90 миллионов - вызовов в секунду на той же машине, что и другие тесты. Поэтому есть надежда, что к тому времени обратный вызов P / Invoking в другом домене приложений будет по-прежнему позволять выполнять миллионы операций в секунду.

90 миллионов в секунду намного ближе к нашей потребности в переключении потоков между доменами приложений.

Хорошо. Теперь вернемся к этому тесту. Цель этого простого модульного теста состоит в том, чтобы сначала получить простые обратные вызовы из неуправляемого в управляемый код, работающий .... после этого следующим шагом будет создание отдельного домена AppDomain, обратный вызов делегата к нему и передача в неуправляемый код проверить производительность междоменного обратного вызова.

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

Вот неуправляемый код, созданный как DLL без параметра командной строки / CLR:

#include <windows.h>

typedef void (CALLBACK *PFN_MYCALLBACK)();
int count = 0;

extern "C" {
    __declspec(dllexport) void __stdcall DoSomeStuff() {
        ++count;
    }
}

extern "C" {
    __declspec(dllexport) void __stdcall DoCallBack(PFN_MYCALLBACK callback) {
        PFN_MYCALLBACK();
    }
}

Вот код модульного теста C #.

using System.Runtime.InteropServices;
using System.Security;
using NUnit.Framework;

namespace TickZoom.Callback
{
    [SuppressUnmanagedCodeSecurity]
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void MyCallback();

    [TestFixture]
    class CrossAppDomainTesting
    {
        public int count;
        [Test]
        public void TestCallback()
        {
            NativeMethods.DoCallBack(
                delegate()
                {
                    ++count;
                });
            Assert.AreEqual(1, count);
        }

        [Test]
        public void TestDate()
        {
            NativeMethods.DoSomeStuff();
        }
    }

    public static class NativeMethods
    {
        [SuppressUnmanagedCodeSecurity]
        [DllImport("CrossAppDomain.dll")]
        public static extern void DoSomeStuff();

        [SuppressUnmanagedCodeSecurity]
        [DllImport("CrossAppDomain.dll")]
        public static extern void DoCallBack(MyCallback callback);

    }
}

1 Ответ

2 голосов
/ 09 января 2012

Первый комментатор к посту решил проблему кодирования.Я ждал, что он отправит это как ответ, чтобы дать ему кредит.Если он это сделает, то я это сделаю.

Это просто опечатка в вашей функции DoCallback?У вас есть PFN_MYCALLBACK ().Я думаю, что вы хотите, чтобы это был обратный вызов ().- Джим Мишель

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

Сначала вы вызываете неуправляемый метод для отправки черезделегат неуправляемого кода, который маршалируется на указатель функции.

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

Наше тестирование показывает, что это работает со скоростью 90 миллионов вызовов в секунду.по сравнению с 300 миллионами в секунду простого вызова C # на интерфейсе или Interlocked.Increment (), который составляет 80 миллионов в секунду.

Другими словами, это достаточно быстро, чтобы происходить довольно часто с потоками переходачерез границы AppDomain.

ПРИМЕЧАНИЕ: есть пара вещей, с которыми нужно быть осторожным.Если вы сохраните указатели на выгружаемые домены приложений, а затем попытаетесь вызвать их, вы получите исключение в отношении собранного делегата.Это объясняется тем, что указатель функции, который дает вам CLR, не просто указатель на функцию в коде.Вместо этого это указатель на кусок «громкого» кода, который сначала проверяет, что делегат все еще присутствует, и выполняет небольшую домашнюю работу для перехода от неуправляемого к управляемому коду.

Наш план состоит в том, чтобы назначить каждый домен AppDomainцелочисленный дескриптор.Тогда неуправляемый код получит и «дескриптор», и указатель функции для помещения в массив.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...