#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'ы. Асинхронный вызов синхронных методов
Комментариев нет:
Отправить комментарий