views:

145

answers:

1

What happens if you call dispatcherOperation.Wait() on an operation that has already completed? Also, the docs say that it returns a DispatcherOperationStatus, but wouldn't that always be Completed since it (supposedly) doesn't return until it's done?

I was trying to use it like this:

    private void Update()
    {
        while (ops.Count > 0) ops.Dequeue().Wait();
    }

    public void Add(T item)
    {
        lock (sync)
        {
            if (dispatcher.CheckAccess())
            {

                list.Add(item);
                OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));

            }
            else
            {
                ops.Enqueue(dispatcher.BeginInvoke(new Action<T>(Add), item));
            }
        }
    }

I'm using this in WPF, so all the Add operations have to occur on the UI thread, but I figured I could basically just queue them up without having to wait for it to switch threads, and then just call Update() before any read operations to ensure that the list is up to date, but my program started hanging.

+1  A: 

i think i know why it is hanging.

you should read through the docs on DispatcherOperation.Wait there is a warning about calling wait on the same thread that the operation has been dispatched too. So what could be happening is that there is a Operation pending on the event queue, but then you call Wait on that operation from the GUI Thread so because wait is blocking the operation will never be dispatched so you have just deadlocked the guithread.

What you could do if you wanted to be absolutely sure that there were no pending events would be to just look at the Status field of operations in the queue, you can remove any that are Completed and if there are any that are not completed you will simply have to try again later.

Though honestly you would probably be better off just not worrying about it and handling the Collectionchanged notifications instead, that way you will be informed exactly when new elements are there and you wont have to worry about pending actions at all.

luke
Oh...that makes sense. I read that warning, but I didn't realize how it would actually occur. "Try again later" is not exactly a simple thing to implement when the program is expecting the result immediately, and I don't think I can listen for the `CollectionChanged` events either because they won't fire until the operation is complete, which I can't complete unless the list is up to date... catch-22. Probably not worth the headache of parallelizing it at all. I'll take the minor performance hit ;)
Mark
I don't understand why you can't use the CollectionChanged event. Do you need to do something before the operations execute? Or are you just worried about latency of the events firing?
luke
Hrm? I'm thinking about a case where I add a bunch of elements to my collection. They're all dispatched asynchronously. Then I try to read or remove one of those new elements. Since they haven't been added to my collection yet, this will fail. Hence the `Update()` function. How will `CollectionChanged` help me here? I don't need to know *when* the elements are added, I just need to know that they *are* there before I perform any reads.
Mark
PS: I'm not really worried about how long it takes for the elements to actually get added, as long as it's not a ridiculously long time (it's really just for the UI), however, they do need to be present before I start popping them off, which could be milliseconds later, or minutes later.
Mark
Please explain your use case, when will you be calling Update() or trying to possibly remove something that isn't there yet? is this user driven based on GUI operations on a bound control? or is something else going on?
luke