Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 11.11.21 21:46
Оценка:
Приветствую.
Для синхронизации потоков и UI выбрал следующее:
public void Invoke(MethodInvoker methodToInvoke)
{
    if (Disposing || IsDisposed) return;
    if (InvokeRequired)
    {
        BeginInvoke(methodToInvoke);
    }
    else
    {
        methodToInvoke();
    }
}

private void RefreshUI()
{
    Invoke(delegate
    {
    // взаимодействие UI
    });
}


Использую BeginInvoke, потому что на Invoke процесс зависал при закрытии формы. Подсказку нашёл там: http://rsdn.org/forum/dotnet.gui/1869795.flat#1869795
Автор: busybox
Дата: 27.04.06
, поэтому и тему так назвал.

Но сейчас возникла необходимость возвращать данные из UI.
Сделал так:
public object InvokeReturn(Func<object> methodToInvoke)
{
    if (Disposing || IsDisposed) return null;
    if (InvokeRequired)
    {
        var result = BeginInvoke(methodToInvoke);
        var ret = EndInvoke(result);
        return ret;
    }
    else
    {
        return methodToInvoke();
    }
}

private object ReturnObject()
{
    return (object)InvokeReturn(delegate
    {
        return (object)uiControl.Text;
    });
}


И теперь опять при закрытии формы зависаю на EndInvoke. Что не так?
Вселенная бесконечна как вширь, так и вглубь.
Re: Зависаю на Invoke (2)
От: Quebecois Канада https://www.canada.ca/
Дата: 11.11.21 22:58
Оценка: 7 (2) +1
Здравствуйте, Real 3L0, Вы писали:

Возьми с полки SynchronizationContext и не придумывай себе проблемы.
Последовательность такая:
1. Из главного потока после создания формы сохраняем SynchronizationContext.Current куда-нибудь
2. Из другого потока вызываем на нем Send().

Работать будет без привязки к конкретным формам, пока главный поток свободен (ЕМНИП, это даже работает для WaitHandle.Wait()).
Re: Зависаю на Invoke (2)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.11.21 23:35
Оценка:
Здравствуйте, Real 3L0, Вы писали:

R3>И теперь опять при закрытии формы зависаю на EndInvoke. Что не так?


Вызванный через BeginInvoke метод попадает в очередь сообщений формы. А при закрытии форма перестает обрабатывать сообщения из очереди. Т.е. ожидание нельзя делать принудительным, если форма закрывается. Мне кажется, что даже свойство Disposing тут отслеживать слишком поздно. Т.е. если в текущий момент форма еще не Disposing, то не факт, что BeginInvoke успеет на паровоз закрытия формы, т.к. не-UI поток может подзаснуть и проспать закрытие.

И тут дело не в форме Invoke/SynchronizationContext/await async...

Пока возврат метода не требовался, видимо, выполнение его никак не контролировалось. С необходимостью получить возврат, оказалось, что гарантий выполнения никто дать не может.
Re: Зависаю на Invoke (2)
От: vaa  
Дата: 12.11.21 01:16
Оценка:
Здравствуйте, Real 3L0, Вы писали:

R3>И теперь опять при закрытии формы зависаю на EndInvoke. Что не так?


непонятно, что это или
winforms :
        public static void InvokeExecute(Action action, Control control)
        {
            if (control.InvokeRequired)
            {
                control.Invoke(action);
                return;
            }

            action();
        }

wpf:
        await Task.Run(async () =>
                    System.Windows.Application.Current.Dispatcher.Invoke(delegate ()
                    {
                        CheckList.Add(check);
                        OnPropertyChanged(nameof(CheckList));
                    }));
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 07:52
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>непонятно, что это или

vaa>winforms :
vaa>
vaa>        public static void InvokeExecute(Action action, Control control)
vaa>        {
vaa>            if (control.InvokeRequired)
vaa>            {
vaa>                control.Invoke(action);
vaa>                return;
vaa>            }

vaa>            action();
vaa>        }
vaa>


Вроде видно, что это.
Вселенная бесконечна как вширь, так и вглубь.
Re[2]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 10:14
Оценка:
Здравствуйте, Quebecois, Вы писали:

Q>Возьми с полки SynchronizationContext и не придумывай себе проблемы.


Пробую разобраться.
Читаю https://habr.com/ru/post/232169/
Пример из статьи, содержащий "mToolStripButtonThreads_Click" в отдельном проекте работает вообще без изменений.
А пытаюсь занести себе в проект и какой-то шантан:
1.
В параметрах uiContext.Post требуется UpdateUI, возвращающий результат SendOrPostCallback

2.
Если указать, как в предыдущем пункте, то метод UpdateUI, продолжает выполняться в том же потоке, откуда он и вызван.

Проекты в обоих случаях одинаковые: Net 5.0.
Как такое возможно?
Вселенная бесконечна как вширь, так и вглубь.
Re[2]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 10:33
Оценка:
Здравствуйте, samius, Вы писали:

S>И тут дело не в форме Invoke/SynchronizationContext/await async...

S>Пока возврат метода не требовался, видимо, выполнение его никак не контролировалось. С необходимостью получить возврат, оказалось, что гарантий выполнения никто дать не может.

Т.е. ты намекаешь на то, что можно оставить как есть, но при закрытии формы не давать её закрывать, пока не погашу все потоки?
Вселенная бесконечна как вширь, так и вглубь.
Re[3]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 14:27
Оценка:
R3>Пробую разобраться.
R3>Читаю https://habr.com/ru/post/232169/
R3>Пример из статьи, содержащий "mToolStripButtonThreads_Click" в отдельном проекте работает вообще без изменений.
R3>А пытаюсь занести себе в проект и какой-то шантан:
R3>1.
R3>В параметрах uiContext.Post требуется UpdateUI, возвращающий результат SendOrPostCallback

R3>2.

R3>Если указать, как в предыдущем пункте, то метод UpdateUI, продолжает выполняться в том же потоке, откуда он и вызван.

Сделал вот так:
uiContext.Post(delegate { UpdateUI (); }, "line " + i.ToString());

Так заработало. В чём причина?

...
И даже не виснет при закрытии.
И методы стали не обёрнутые Invoke'ами.
...
А из-за того, что методы не обёрнутые, то можно дёргать любые методы и возможность передачи значений между ними появилась автоматом.
Вселенная бесконечна как вширь, так и вглубь.
Re[3]: Зависаю на Invoke (2)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.11.21 14:34
Оценка:
Здравствуйте, Real 3L0, Вы писали:

R3>Здравствуйте, samius, Вы писали:


S>>И тут дело не в форме Invoke/SynchronizationContext/await async...

S>>Пока возврат метода не требовался, видимо, выполнение его никак не контролировалось. С необходимостью получить возврат, оказалось, что гарантий выполнения никто дать не может.

R3>Т.е. ты намекаешь на то, что можно оставить как есть, но при закрытии формы не давать её закрывать, пока не погашу все потоки?

нет, я на такое не намекал. Я намекал на то, что потоки могут не получить возвраты из UI, т.к. форма уже закрыта. И сделать ситуацию контроллируемой можно лишь тем, что форма, закрываясь, будет отменять все вычисления, данные ей. Можно сделать через Task_и их Source-ы.
Re[4]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 15:22
Оценка:
Здравствуйте, samius, Вы писали:

S>нет, я на такое не намекал. Я намекал на то, что потоки могут не получить возвраты из UI, т.к. форма уже закрыта. И сделать ситуацию контроллируемой можно лишь тем, что форма, закрываясь, будет отменять все вычисления, данные ей. Можно сделать через Task_и их Source-ы.


У меня так и было сделано: при закрытии формы инициировал и ждал
_cancellationTokenSource.Cancel();
_task.Wait();

И процесс зависал.
Вселенная бесконечна как вширь, так и вглубь.
Re[5]: Зависаю на Invoke (2)
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.11.21 15:51
Оценка:
Здравствуйте, Real 3L0, Вы писали:

R3>Здравствуйте, samius, Вы писали:


R3>У меня так и было сделано: при закрытии формы инициировал и ждал

R3>
R3>_cancellationTokenSource.Cancel();
R3>_task.Wait();
R3>

R3>И процесс зависал.
Надо таски отменять через TaskCompletionSource при закрытии формы. Если метод выполнения таска не получил управления, Wait будет бесконечным.
Re[6]: Зависаю на Invoke (2)
От: Real 3L0 Россия http://prikhodko.blogspot.com
Дата: 12.11.21 18:54
Оценка:
Здравствуйте, samius, Вы писали:

S>Надо таски отменять через TaskCompletionSource при закрытии формы. Если метод выполнения таска не получил управления, Wait будет бесконечным.


Да, именно так и было.
Вселенная бесконечна как вширь, так и вглубь.
Re: Зависаю на Invoke (2)
От: VladCore  
Дата: 15.11.21 17:34
Оценка:
Здравствуйте, Real 3L0, Вы писали:

R3>Приветствую.

R3>Для синхронизации потоков и UI выбрал следующее:
R3>
R3>public void Invoke(MethodInvoker methodToInvoke)
R3>{
R3>    if (Disposing || IsDisposed) return;
R3>    if (InvokeRequired)
R3>    {
R3>        BeginInvoke(methodToInvoke);
R3>    }
R3>    else
R3>    {
R3>        methodToInvoke();
R3>    }
R3>}

R3>private void RefreshUI()
R3>{
R3>    Invoke(delegate
R3>    {
R3>    // взаимодействие UI
R3>    });
R3>}
R3>


R3>Использую BeginInvoke, потому что на Invoke процесс зависал при закрытии формы. Подсказку нашёл там: http://rsdn.org/forum/dotnet.gui/1869795.flat#1869795
Автор: busybox
Дата: 27.04.06
, поэтому и тему так назвал.


R3>Но сейчас возникла необходимость возвращать данные из UI.

R3>Сделал так:
R3>
R3>public object InvokeReturn(Func<object> methodToInvoke)
R3>{
R3>    if (Disposing || IsDisposed) return null;
R3>    if (InvokeRequired)
R3>    {
R3>        var result = BeginInvoke(methodToInvoke);
R3>        var ret = EndInvoke(result);
R3>        return ret;
R3>    }
R3>    else
R3>    {
R3>        return methodToInvoke();
R3>    }
R3>}

R3>private object ReturnObject()
R3>{
R3>    return (object)InvokeReturn(delegate
R3>    {
R3>        return (object)uiControl.Text;
R3>    });
R3>}
R3>


R3>И теперь опять при закрытии формы зависаю на EndInvoke. Что не так?


Юзай замыкания вместо EndInvoke. Заодно как результат линейный код останется линейным исходным кодом.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.