2014-02-20 2 views
0

Я разрабатываю сервер онлайн-игр, который использует C# для своих сценариев NPC. Чтобы получить NPC без гражданства, я использую счетчики, уступая, когда мне нужно ждать ответа от клиента и вызывать MoveNext, как только я его получу.Отмена ожидающих задач без явных проверок

Talk() 
    Msg("test"); 
    Select("Yes", "No"); 
    yield return true; 
    Msg(Response); 

(упрощенный пример, податливость является немного более сложным, на самом деле.)

Это работает отлично, но асинхронная/ожидание бы сделать его чище, проще и более гибким.

Talk() 
    Msg("test"); 
    Msg(await Select("Yes", "No")); 

Игра вокруг с асинхронным/ждать, я нашел свою единственную проблему в том, что сценарии не так просто, как отправка некоторых сообщений. При вызове других функций из основной функции Talk я должен их ждать, так как выполнение не останавливается иначе. Другие функции могут также вызвать еще больше, создавая неизвестное количество ожиданий.

Talk() 
    Msg("test"); 
    await OtherTalk(); 
    Msg("end"); // would be called right away 

OtherTalk() 
    Msg("test2"); 
    Msg(await Select("Yes", "No")); 

Если я закрываю NPC внутри такого метода «к югу от разговора» Я бы потенциально оставить немало задач висит в воздухе, потому что не будет возвращаться вверх по цепочке. NPC закрыт, больше нет ответов, задачи ждут.

Решение этой проблемы будет возвращаться в цепочку с явными проверками после ожидания такой функции, чтобы проверить, был ли NPC закрыт где-то по линии. Но я хочу, чтобы они были такими же простыми и прямыми, насколько это возможно, и, честно говоря, иметь, если после каждого вызова функции будет слишком утомительно для моего вкуса. Серверное программное обеспечение также будет использоваться новичками, которые могут забыть такую ​​проверку, что может привести к проблемам, в зависимости от того, что делает скрипт.

Мой вопрос сейчас, если кто-то может подумать о способе отмены Заданий, без явных проверок в самих скриптах.

+4

Используйте встроенные функции отмены TPL; см. «CancellationTokenSource». – SLaks

+0

Это потребует проверки в сценариях, потому что задачи будут возвращены, а «родительские» функции не должны продолжать выполнение. – Mars

+2

Нет; ожидание отмененной задачи также отменит вызывающего абонента. Вам просто нужен периодический вызов token.ThrowIfCancellationRequested(). – SLaks

ответ

3

TPL имеет встроенные функции отмены.

Сделать все ваши функции принятыми CanellationToken и передать токен при вызове каждой асинхронной функции.

Время от времени, внутри функций, звоните token.ThrowIfCancellationRequested(), и весь асинхронный звонок будет отменен, пока вы не обработаете отмену.

0

Это короткий ответ.

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

+0

безопасно или безопасно? – Aron

+0

@ Арон, который работает для вас. Я - равная возможность. – Gusdor

+0

Я действительно надеюсь, что это была шутка ... так как это на самом деле делает какой-то смысл ... – Aron

1

Вы можете установить пользовательский SynchronizationContext, который вы можете отменить. При отмене он просто прекратил называть продолжения. Методы async эффективно прекратили бы сразу после следующего await. Если ничто не держит за эти задачи, они будут GC'ed и просто уйдут.

Помните, что таким образом даже блокировки finally не выполнялись. using очистки не будет происходить и т. Д. В этих обстоятельствах ваш код должен быть затвердевшим.

+0

Хотя похоже, что я не буду использовать этот метод, было очень интересно читать SynchronizationContext, никогда не слышал о это (возможно, потому, что я редко программирую GUI). И это была очень интересная идея, +1. – Mars

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