1

Это может быть гораздо более общий вопрос, связанный с тем, как лучше всего отменить блокировку заданий на других потоках, но меня интересует решение в контексте Grand Central Dispatch. Мне нужно вызвать функцию, которая в основном блокирует, пока не получит данные из сети; он может быть заблокирован навсегда. Теперь я настроил его так, чтобы этот заблокированный вызов выполнялся в частной очереди отправки, и когда я получаю данные, я помещаю блок обратно в основную очередь. Проблема в том, что, как только я отправляю свой приватный вызов и блокирующий вызов, я никогда не могу отменить это. Представьте, что эта способность была привязана к пользовательской настройке. Если бы они отключились, я бы хотел, чтобы это блокирующее задание и блок выполнения по существу просто заканчивались. Есть ли хорошее решение этой проблемы?Есть ли шаблон для отмены блока в другой очереди отправки?

Благодаря

- (void)_beginListeningForNetworkJunk 
{ 
    dispatch_async(my_private_queue, ^{ 
     // blocks until it gets data 
     id data = [NetworkListener waitForData]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self _handleNetworkData:data]; 
     }); 
    }); 
} 

- (void)_endListeningForNetworkJunk 
{ 
    // How do I kill that job that is blocked on my private queue? 
} 

ответ

1

Вы не можете. Проблема заключается в NetworkListener в своем блокирующем и бесперебойном интерфейсе.

Как правило, вы кодируете блок для асинхронного обслуживания сетевого подключения, а также для мониторинга другого механизма сигнализации, такого как собственный источник цикла запуска (или NSPort или дескриптор файла канала или ...). Когда сетевое соединение имеет активность, это будет обслуживаться. Когда срабатывает сигнальный механизм, вы должны отключить сетевое соединение и выйти из блока.

Таким образом, блок может быть аннулирован при сотрудничестве.

Поскольку ваш блок застрял в -waitForData, он не может сотрудничать. Механизм отмены блоков без их сотрудничества отсутствует. То же самое относится к NSOperation и NSThread. Причина в том, что практически невозможно прекратить деятельность другого потока без его сотрудничества.

Вам нужен другой дизайн для вашего сетевого кода.

+0

Darn. API, который я использую, не мой. Его структура. –

+0

Является ли это общедоступной структурой (например, с открытым исходным кодом)? –

0

В принципе, вы не можете отменить что-либо, работающее на любой другой теме. Вы можете только вежливо попросить задачу, которая работает в другом потоке, отменить. Обычно я создаю объекты, представляющие задачи, так что на эти объекты можно вызвать «cancel».

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

В _endListenForNetworkJunk вы можете установить значение BOOL «отменено», чтобы указать, что вызов отменен. Затем в коде, который выполняется в основной очереди, проверьте, все ли это значение отменено. Таким образом, если вы вызываете _endListenForNetworkJunk из основного потока, вы уверены, что _handleNetworkData не будет вызван. Если вы вызываете _endListenForNetworkJunk из другого потока, основной поток мог бы просто запустить вызов _handleNetworkData.

Если вы отметили «отменено» непосредственно перед отправкой в ​​основную очередь, этот блок уже может быть отправлен, но не выполняется непосредственно перед тем, как вы вызовете _endListenForNetworkJunk в основном потоке.