Пример элементарной очереди сообщений
Я хотел бы поделиться рудиментарной очередью сообщений, которую я однажды написал для своих собственных исследований. Это может помочь составить представление о возможной реализации очереди сообщений. Нет претензий на полноту, целостность или отсутствие ошибок, и, вероятно, в большинстве случаев есть лучшие решения, чем использование пользовательской очереди сообщений.
public void run()
{
while (running)
{
mainLoopWaitHandle.WaitOne();
EventHandlerFunction f = null;
while (running)
{
f = popEvent();
if (f == null) break;
f();
}
}
}
private void pushEvent(EventHandlerFunction handlerFunction)
{
lock (eventQueueLock)
{
int b = (queueInIndex + 1) & 255;
if (b == queueOutIndex)
{
throw new Exception("Buffer overflow in event queue.");
}
eventQueue[queueInIndex] = handlerFunction;
queueInIndex = b;
mainLoopWaitHandle.Set();
}
}
private EventHandlerFunction popEvent()
{
EventHandlerFunction ret = null;
lock(eventQueueLock)
{
int b = (queueOutIndex + 1) & 255;
if (queueOutIndex == queueInIndex)
{
mainLoopWaitHandle.Reset();
return null;
}
ret = eventQueue[queueOutIndex];
eventQueue[queueOutIndex] = null;
queueOutIndex = b;
}
return ret;
}
Основной поток начинает использовать очередь сообщений с запуска run()
. run()
- это метод блокировки, который не возвращается до тех пор, пока атрибут класса running
не будет установлен в false
. Это можно сделать с помощью метода invoker, описанного ниже.
Для вызова метода в главном потоке нужны два метода. Одна функция EventHandlerFunction (скажем, метод A()
), которая фактически вызывается в основном потоке, и метод B()
, который выполняется в потоке вызывающей стороны. Я вижу это аналогично функциям пользовательского интерфейса, где B()
- это метод формы, а A()
get's Invoke
d из B()
.
B()
вызывает A()
, вызывая
pushEvent(A);
, в то время как pushEvent()
и popEvent()
- сохранение потока.
Цель метода B()
- сохранить любые объекты или параметры в некоторой структуре данных для передачи данных, которая представляет параметры (или задачи) для метода A()
. Эта структура может быть List<>
с рабочими элементами, например. Метод A () и B () оба должны позаботиться о правильной блокировке этой структуры для безопасности потока.
Метод A()
также должен учитывать, что буфер может заполниться полностью либо в очереди сообщений, либо в собственной структуре передачи данных) и должен заботиться о последствиях (например, сбросить вызов или заблокировать вызов, пока не освободится место). в стеке).
Надеюсь, это поможет. Взносы приветствуются.