2010-03-30 1 views
3

У меня проблемы. Я пытаюсь подражать вызову Application.Run с использованием Application.DoEvents ... это звучит плохо, а затем я принимаю также альтернативные решения по моему вопросу ...«Эмуляция» Application.Run using Application.DoEvents

Мне нужно обработать сообщение, например, приложение Application.Run но мне нужно выполнить код до и после обработки сообщений. Вот главный существенный фрагмент кода.

// Create barrier (multiple kernels synchronization) 
sKernelBarrier = new KernelBarrier(sKernels.Count); 

foreach (RenderKernel k in sKernels) { 
    // Create rendering contexts (one for each kernel) 
    k.CreateRenderContext(); 
    // Start render kernel kernels 
    k.mThread = new Thread(RenderKernelMain); 
    k.mThread.Start(k); 
} 

while (sKernelBarrier.KernelCount > 0) { 
    // Wait untill all kernel loops has finished 
    sKernelBarrier.WaitKernelBarrier(); 
    // Do application events 
    Application.DoEvents(); 
    // Execute shared context services 
    foreach (RenderKernelContextService s in sContextServices) 
     s.Execute(sSharedContext); 

    // Next kernel render loop 
    sKernelBarrier.ReleaseKernelBarrier(); 
} 

Этот фрагмент кода выполняется основной процедурой. Pratically У меня есть список классов ядра, который работает в отдельных потоках, эти потоки обрабатывают форму для рендеринга в OpenGL. Мне нужно синхронизировать все потоки ядра с помощью барьера, и это отлично работает. Конечно, мне нужно обрабатывать сообщения формы в основном потоке (основная процедура), для каждой созданной формы, и я действительно вызываю Application.DoEvents() для выполнения задания.

Теперь я должен изменить фрагмент выше, чтобы иметь общую форму (простое диалоговое окно), не потребляя 100% процессорного вызова Application.DoEvents(), как Application.Run.

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

Как это возможно?

Примечание: фрагмент выше должен быть выполнен в основной процедуре, так как контекст OpenGL создается в основном потоке. Перемещение фрагмента в отдельной ветке и вызов Application.Run довольно неустойчиво и багги ...

ответ

1

Нет ничего принципиально неправильного в вызове Application.DoEvents() в цикле. Это то, что делает Form.ShowDialog(). Он принимает контрмеры, чтобы гарантировать, что пользователь не может попасть в проблему: он отключает все окна, отличные от диалогового окна, чтобы пользователь не мог выйти из приложения или снова запустить диалог.

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

Вам потребуется процессор, чтобы избежать 100% загрузки процессора.Самый простой способ сделать это - вызвать Thread.Sleep (1). Ответьте на мой ответ в this thread.

+0

Яйцо Колумба. Спасибо. – Luca

+0

Nitpicking and - dupid: Существует много дискуссий о 'Thread.Sleep (0)' vs 'Thread.Sleep (1)' down down .. –

1

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

Вы не можете использовать Application.AddMessageFilter(), чтобы реализовать то, что вам нужно?

+0

Я могу обработать конкретное сообщение для выдачи рендеринга, но мне интересно, как включить цикл, который отображает как можно больше. Повторно отправляет сообщение из разделенного потока? (И это подразумевает использование Application.Run вместо этого фрагмента, который усложняет использование барьера) – Luca

+1

Просто отправьте сообщение (не отправляйте!) Сообщение, которое вы обрабатываете, и в конце обработчика повторно разместите одно и то же сообщение еще раз. Это создает бесконечный цикл, сохраняя при этом все остальное. – Lucero

0

Если вы собираетесь создать такой цикл сообщений, вы должны выполнить PInvoke фактические функции обработки сообщений Win32 (это все, что Application.Run делает за кулисами - он имеет внутренний класс UnSafeNativeMethods, который отображает куча их).

Если вам не нужно продолжать обработку между вызовами сообщений - другими словами, если безопасно, чтобы ваш поток спал, когда он не активно обрабатывал сообщение, - тогда свяжите WaitMessage с User32.dll и поместите его в петля как:

while (WaitMessage()) 
{ 
    Application.DoEvents(); 
} 

Если вам нужна дополнительная помощь, дайте мне знать. Я сейчас нахожусь в середине переустановки VS, или я бы разместил образец приложения, показывающий, как сделать привязку и PInvoke.

+0

Хотелось бы избежать PInvoke (или, по крайней мере, с конкретным PInvoke для WIN32, X11 и OSX) ... сон не звучит хорошо, не так ли? – Luca

+1

Ах. Если вы пытаетесь написать что-то кросс-платформенное, то Application.DoEvents() в цикле так же хорошо, как вы собираетесь получить, к сожалению. Конструкция сообщения сообщения между Win32, X11 и OSX очень отличается, и хотя структура Mono хорошо справляется с тем, чтобы скрыть это от вас и сделать все это похожим на архитектуру Win32, она не подвергает любой мелкозернистый контроль работе с его абстракцией. –