Делегат, BeginInvoke. EndInvoke - Как очистить несколько вызовов асинхронных угроз одному и тому же делегату? - PullRequest
3 голосов
/ 09 февраля 2010

Я создал делегата, которого я собираюсь вызвать Async.

Уровень модуля

Delegate Sub GetPartListDataFromServer(ByVal dvOriginal As DataView, ByVal ProgramID As Integer)
Dim dlgGetPartList As GetPartListDataFromServer 

Следующий код, который я использую в методе

    Dim dlgGetPartList As New GetPartListDataFromServer(AddressOf AsyncThreadMethod_GetPartListDataFromServer)
    dlgGetPartList.BeginInvoke(ucboPart.DataSource, ucboProgram.Value, AddressOf AsyncCallback_GetPartListDataFromServer, Nothing) 

Метод работает и делает то, что ему нужно

Асин обратный вызов запускается после завершения, когда я делаю EndInvoke

Sub AsyncCallback_GetPartListDataFromServer(ByVal ar As IAsyncResult)
    dlgGetPartList.EndInvoke(Nothing)
End Sub

Он работает до тех пор, пока метод, который запускает BeginInvoke на делегате, выполняется только когда операция BeginInvoke / Thread еще не запущена. Проблема заключается в том, что новый поток может быть вызван, пока другой поток в делегате все еще работает и еще не был EndInvoke'd.

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

Что такое чистое решение и лучшая практика для преодоления этой проблемы?

Ответы [ 2 ]

2 голосов
/ 09 февраля 2010

Вам нужно только удержать одну ссылку на делегата; вам не нужно создавать новый каждый раз, когда вы вызываете.

Вместо передачи Nothing в EndInvoke, передача ar. Это даст вам результат этого конкретного вызова.

Sub AsyncCallback_GetPartListDataFromServer(ByVal ar As IAsyncResult)
    dlgGetPartList.EndInvoke(ar)
End Sub

Если вы хотите иметь возможность отменить определенный вызов, то вам нужно сохранить результат BeginInvoke (который является тем же экземпляром IAsyncResult, который передается вам в вашем обратном вызове выше) .

1 голос
/ 09 февраля 2010

Вам нужно передать объект в качестве аргумента состояния при вызове BeginInvoke.

    class Program

    {
        delegate void SampleDelegate(string message);

        static void SampleDelegateMethod(string message)
        {
            Console.WriteLine(message);
        }
        static void Callback(object obj)
        {
            IAsyncResult result = obj as IAsyncResult;

            SampleDelegate del = result.AsyncState as SampleDelegate; 
            del.EndInvoke(result);
            Console.WriteLine("Finished calling EndInvoke");
        }
        static void Main()
        {
            for (int i = 0; i < 10; i++)
            {
                // Instantiate delegate with named method:
                SampleDelegate d1 = SampleDelegateMethod;
               //d1 is passed as a state
                d1.BeginInvoke("Hello", Callback, d1);
            }
            Console.WriteLine("Press any key to continue");
            Console.ReadLine();
        }
    }
...