Страницы

Поиск по вопросам

вторник, 7 января 2020 г.

Асинхронность. Почему не работает обработчик события?

#c_sharp


Господа программисты. Прошу вашей помощи. Разбираюсь с асинхронным программированием
и иногда возникают некоторые сложности.  Вот есть такой класс:

delegate void simpleDelegate(int progress);
class Calculations  
{  
    public event simpleDelegate Progresschanged;  
    public int getsquare(int digit)  
    {  
        for (int i = 0; i <= 100; i++)  
           if (Progresschanged != null)  
                Progresschanged(i);  
        return digit * digit;  
    }  
}

и есть форма, где по нажатию кнопки запускается метод класса в асинхронном режиме:
delegate int myDel(int r);
 private void button1_Click(object sender, EventArgs e)
    {
        Calculations calc = new Calculations();
        calc.Progresschanged += delegate(int r)
        {
            this.Invoke(new MethodInvoker(() =>
            {
                progressBar1.Value = r;
            }));
        };

        myDel deleg = calc.getsquare;            
        IAsyncResult res = deleg.BeginInvoke(12, null, null);            
        int k = deleg.EndInvoke(res);
        listBox1.Items.Add(k);
    }

Не знаю почему, но приложение намертво зависает. Причём, если не использовать асинхронность,
а сделать типа такого:    

myDel deleg = calc.getsquare;            
deleg(12);

то всё работает. Что мне исправить, но не убирая асинхронности?    


Ответы

Ответ 1



Насколько я понимаю, у вас присутствует взаимная блокировка. Вот что у вас происходит в главном потоке: Сначала вызывается button1_Click() Затем в этом методе создается новый поток для асинхронного выполнения getsquare() Далее сразу же вызывается EndInvoke(), тем самым блокируя главный поток до тех пор, пока не будет выполнен getsquare() Теперь, что происходит в новом потоке: Запускается выполнение getsquare() Затем дергается событие, на которое был подписан делегат из метода button1_Click() Далее в этом делегате вызывается Invoke() сигнализируя диспетчеру потоков о том, что в главном потоке необходимо выполнить некоторое действие. Блокируется в освобождении главного потока. Однако главный поток не будет освобожден никогда, поскольку заблокирован в EndInvoke(). Решение проблемы: использовать Callback. IAsyncResult res = deleg.BeginInvoke(12, new AsyncCallback(Complete), null); // ... void Complete(IAsyncResult ar) { var caller = (myDel) ((AsyncResult) ar).AsyncDelegate; int k = caller.EndInvoke(ar); // ... }

Ответ 2



Ну у Вас тут нифига не асинхронность: int k = deleg.EndInvoke(res); Данный код будет ждать результата. И вешать поток нахрен. И, кстате, вы понимаете что этот код будет выполняться в том же потоке, так же что тоже не будет в чистом виде "Асинхронно". По факту, этим кодом(BeginInvoke) вы ставите в очередь на выполнение указанную функцию, если придут какие-либо другие события то они будут ждать завершения работы делегированного кода (будут в очереди за ним). А зависание происходит от того что вы ставите в очередь на выполнения делегата, и ожидаете завершение его, а он не может даже запуститься т.к. вы не вышли из обработки кнопки. Наверное вам лучше прочитать про Thread'ы. Асинхронный вызов синхронных методов

Комментариев нет:

Отправить комментарий