Invoke() is blocking

前端 未结 4 2302
慢半拍i
慢半拍i 2021-02-12 12:49

From time to time my applications GUI stops redrawing. There a lot of threads that are firing all kinds of events (like timers or network data ready etc.). Also there are a lot

相关标签:
4条回答
  • 2021-02-12 13:07

    Invoke waits until the event is handled in the GUI thread. If you want it to be asynchronous use BeginInvoke()

    0 讨论(0)
  • 2021-02-12 13:19

    From watching this question, I can see that you're not going to get any answers that will fix the problem immediately, as most of them require you to debug the event, and it happens so infrequently that this is nearly impossible. So, let me suggest you make some code changes that might help you identify the culprit in the field.

    I suggest that you create a static class whose sole purpose is to handle all your Invoke calls. I would suggest that this class has a method that takes a Control, (to call Invoke on) an Action (the method to be invoked), and a description (containing the information you would need to know to identify the method and what it is going to do).

    Within the body of this method, I suggest you enqueue this information (method, description) and return immediately.

    The queue should be serviced by a single thread, which pops the action/message pair off the queue, records the current time and the Action's description in a pair of properties, and then Invokes() the Action. When the Action returns, the description and time are cleared (your DateTime can be nullable, or set it to DateTime.Max). Note, since all Invokes are marshalled one at a time onto the UI thread, you're not losing anything by servicing the queue by a single thread here.

    Now, here's where we get to the point of this. Our Invoking class should have a heartbeat System.Threading.Timer thread. This should NOT be a windows.forms.timer object, as that runs on the UI thread (and would be blocked when the ui is blocked!!!).

    The job of this timer is to periodically peek at the time the current Action was Invoked. If DateTime.Now - BeginTime > X, the heartbeat timer will decide that this Action has blocked. The heartbeat timer will LOG (however you log) the DESCRIPTION recorded for that Action. You now have a recording of what was happening at the time your UI locked up and can debug it better.

    I know it's not an answer to your problem, but at least by doing this you can get a good idea about what's going on at the time you're blocked.

    0 讨论(0)
  • 2021-02-12 13:23

    The most likely answer (deadlock) has already been suggested.

    Another way to simulate this behaviour is to reduce the number of pool threads and IO completion ports; you haven't called ThreadPool.SetMaxThreads(...) by any chance?

    0 讨论(0)
  • 2021-02-12 13:24

    Deadlock perhaps? Do you make sure that the events are never fired while holding a lock?

    Are you able to see this with a debugger attached? If so, make it freeze and then hit the "pause" button - and see what the UI thread is doing.

    Note that if you are able to get away with BeginInvoke instead of Invoke, life is a bit easier as it won't block.

    Also note that you don't need the "new EventHandler" bit - just

    Invoke((EventHandler) MyEventHandler, sender, e);
    

    should be fine.

    0 讨论(0)
提交回复
热议问题