2017-02-07 9 views
2

У меня есть следующая проблема. У меня есть программное обеспечение, которое имеет доступ к части оборудования, подключенного через USB.Избегайте блокировки пользовательского интерфейса из-за блокировки в WPF

В интерфейсе есть несколько кнопок (например, поиск устройства и т.д.)

И вы можете создать задачу, которая будет блокировать ресурс (USB устройство) и выполняет много времени работы в фоновом потоке.

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

У меня есть несколько идей, как решить это, но у всех, похоже, много недостатков.

Мои идеи до сих пор:

  • Проверить с Monitor.TryEnter, если ресурс доступен. ## Недостаток заключается в том, что для этого требуется, чтобы я изменил все реализации ICommand (добавьте оператор if)

  • Создайте еще одну реализацию ICommand, которая имеет блокировку в качестве дополнительного параметра и выполняет этот метод только в том случае, если эта блокировка свободна (я бы хотел иметь его как предопределенный оператор CanExecute). ## Проблема в том, что я не уверен, что изменение CanExecute будет заполнено правильно (я мог бы создать фоновое задание, которое периодически проверяет, свободен ли ресурс, но я думаю, что это может привести к условиям гонок ...)

Я ищу идеи, как это можно решить, если это не «конструктивный вопрос», не стесняйтесь его отмечать.

Отношения.

+0

Добавить еще один слой между USB и пользовательским интерфейсом? Например, в вашей модели просмотра вместо прямого доступа к USB вы добавляете свойство, которое будет обновляться при обратном вызове, когда задача будет выполнена. – Kilazur

+0

Просто используйте простой булевский флаг вместо блокировки в обработчике кликов кнопок – Evk

+0

Почему у вас есть «блокировка» в пользовательском интерфейсе? – Enigmativity

ответ

1

Внутри вашего Execute() вы можете использовать Interlocked.CompareExchange(), чтобы установить флаг занятости перед тем, как развернуть своего рабочего.

Позже в вашем CanExecute() просто сделайте Interlocked.Read(), чтобы проверить «занятость».

Когда ваш работник завершает работу, просто снимите флаг занятости, выполнив еще один Interlocked.Exchange().

Класс Interlocked является потокобезопасным; достаточно быстро; и вышеупомянутый шаблон не будет блокировать ваш пользовательский интерфейс.

0

Вы можете использовать асинхронную блокировку вокруг своего критического раздела. .NET Framework обеспечивает SemaphoreSlim класс, который имеет асинхронный WaitAsync метод:

System.Threading.SemaphoreSlim _lock = new System.Threading.SemaphoreSlim(1, 1); 

//Asynchronously wait to enter the semaphore... 
await _lock.WaitAsync(); 
try 
{ 
    //do your thing in the critical section 
} 
finally 
{ 
    _lock.Release(); 
} 

Там также является AsyncLock тип, который является асинхронной почти эквивалентна версии ключевого слова блокировки доступны в библиотеке AsyncEx Стивена Клири, которые вы можете использовать: https://github.com/StephenCleary/AsyncEx/wiki/AsyncLock

Используя асинхронную блокировку, вы можете дождаться освобождения блокировки, не блокируя поток пользовательского интерфейса.

 Смежные вопросы

  • Нет связанных вопросов^_^