Ожидание в C # для события в качестве задачи или дескриптора ожидания

Я программирую в основном на .NET, и мне нравятся его асинхронные / параллельные примитивы, такие как Tasks, ResetEvents и т. Д. Сегодня я впервые внес значительные изменения в программу на C ++ и понял, как работает весь процесс сборки (я обновленный Проект LigthningDB.NET до 0.9.14). Но мне все еще не хватает знаний C ++.

Одна новая функция, которую я хочу добавить в проект LMDB (для собственных нужд), — это система уведомлений (похожая на Redis):

  • Мне нужен курсор, возвращающий ожидаемый объект, который будет сигнализировать о каждом изменении данных в своей таблице.
  • Я хочу получить некоторые данные вместе с сигналом (указатель на структуру данных), например, ключ или ключ + значение.
  • Этот объект будет расположен вместе с курсором и является частью курсора, но он сигнализирует об изменениях в БД, для которых курсор имеет ссылку.
  • Это должно работать кроссплатформенный когда-нибудь (или какой-то год). Я в порядке с любыми грязными Windows-специфическими взломами, если они делают эту работу.

Типичный вариант использования — это писатель и N читателей, ожидающих новых сообщений. Это позволит IPC и быстрое сохранение 2-в-1. LMDB поддерживает одновременное чтение из разных процессов (в то время как Esent и LevelDB — нет).

System.Threading Примитивы доступны из C ++, и я понимаю, как использовать WaitHandle для блокирующего вызова. Есть ли способ сделать этот асинхронный? Eсть большая серия статей об асинхронных примитивах синхронизации, но они используют TaskCompletionSource и это работает только внутри .NET. Можно ли сделать подобное решение для родного взаимодействия?

Одним из решений могут быть именованные каналы или сокеты, транслирующие изменения одному слушателю / диспетчеру (Redis или Rhino.Queues стиль), но производительность пострадает: записи должны будут распределять, копировать и передавать данные, а данные должны перемещаться — гораздо хуже, чем передавать указатель на структуру данных, которая уже находится в памяти.

Другой вариант — переместить курсор прослушивания на клавишу и отправить сигнал. После сигнала слушатель C # будет знать, что курсор имеет значения при обновленной клавише. Этот вид решает часть передачи данных, но с WaitHandles это блокировка — в моем случае блокировка хуже, чем комбинация сокетов [размещение / копирование / задержка].

Есть ли лучшие варианты?

Дополнительный вопрос:

  1. Я изобретаю велосипед здесь?
  2. Не могли бы вы указать на библиотеки с открытым исходным кодом, где программа .NET ожидает (не блокирует) сигнал C / C ++ (если они существуют)?
  3. Должен ли я использовать LMDB для этого рабочего процесса? Windows в моем приоритете, и я очень плохо пытался заставить LevelDB работать вообще (перестал пытаться). Есть ли лучшие альтернативы для всего, что делает LMDB + сигнализация?

Обновить

я нашел в документации Этот метод:

public static Task WaitOneAsync(this WaitHandle waitHandle)
{
if (waitHandle == null) throw new ArgumentNullException("waitHandle");

var tcs = new TaskCompletionSource<bool>();
var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle,
delegate { tcs.TrySetResult(true); }, null, -1, true);
var t = tcs.Task;
t.ContinueWith(_ => rwh.Unregister(null));
return t;
}

доктор за ThreadPool.RegisterWaitForSingleObject Говорит, что:

Операция ожидания выполняется нить из пула потоков.
делегат исполняется работником нить когда состояние объекта
сигнализируется или истекает интервал ожидания.

ждать ветку использует Win32 WaitForMultipleObjects функция для мониторинга зарегистрированных операций ожидания.

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

4

Решение

RWFSO использует специальные потоки пула потоков для ожидания нескольких дескрипторов. Существует встроенное ограничение в 63 дескриптора на поток, так что это не так эффективно, как IOCP. Я бы не рекомендовал ручное решение, хотя MRE Можно быть использованы для решения этого (MRE могут быть использованы для решения практически все …).

В C ++ нет понятия «события». Традиционный подход заключается в получении указателя на функцию обратного вызова (которая в сочетании с Boost.Bind а также Boost.Function не так больно в наши дни). Более современный подход будет Boost.Signals2.

3

Другие решения

Обновление: был логический недостаток: чтобы использовать обратный вызов C, должен быть один процесс C и несколько процессов C #. Но с MMF, только память разделяется B / W 2 различных процессов C. Поэтому мне нужен либо сервер C, такой как Redis (но у нас уже есть Redis!), Либо межпроцессная сигнализация.

У меня был опыт работы с надежная синхронизация и редис и это было корнем вопроса — я хотел иметь подобное решение, но для локальной машины с постоянством.

Вероятно, переписать логику Redis с помощью именованных MRE / ARE — это самый простой подход. Как сказал Стивен, MRE может сделать что угодно.


(любые голоса должны идти к ответу Стивена Клири, вот только пример)

Ответ заключается в использовании TaskCompletionSource и Callback для установки его результата.

Пример обратного вызова:

C #:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate int CompareCallback(int a, int b);

[SuppressUnmanagedCodeSecurity]
class NativeMethod
{

[DllImport("CppDynamicLinkLibrary.dll", CharSet = CharSet.Auto)]
public static extern int CompareInts(int a, int b, CompareCallback cmpFunc);

}

C:

// Type-definition: 'PFN_COMPARE' now can be used as type
typedef int (CALLBACK *PFN_COMPARE)(int, int);

// An exported/imported stdcall function using a DEF file
// It requires a callback function as one of the arguments
int __stdcall CompareInts(int a, int b, PFN_COMPARE cmpFunc)
{
// Make the callback to the comparison function

// If a is greater than b, return a;
// If b is greater than or equal to a, return b.
return ((*cmpFunc)(a, b) > 0) ? a : b;
}

образец кода: https://code.msdn.microsoft.com/windowsdesktop/CSPInvokeDll-b05779d0

0

По вопросам рекламы [email protected]