(ОБНОВЛЕНИЕ: По просьбе Панагиотиса Канавоса я постараюсь быть более точным в том, чего я добиваюсь, поэтому я изменил исходный пост).
Мне нужно отменить длительный запрос с CancellationToken.
Скажем, у меня есть метод доступа к данным, похожий на этот:
void DoSomethingLongRunningOnSql(CancellationToken token){
...
}
... и я должен быть в состоянии гарантировать, что независимо от того, что такое время, если источник токена был отменен, этот метод не должен продолжать работать.
Вызывающая сторона может сделать следующее:
var source = new CancellationTokenSource();
var token = source.Token;
В потоке 1 это называется:
DoSomethingLongRunningOnSql(token); // Thread 1
В потоке 2, в то же время источник может быть отменен:
source.Cancel(); // Thread 2
В этом случае я хочу, чтобы длительный запрос просто останавливался независимо от того, является ли источник был отменен до начала или после запроса.
Я не могу использовать методы Asyn c классов Sql здесь, так как это должно работать в существующем контексте syn c. А переключение между syn c и asyn c склонно к проблемам с блокировкой.
Исходя из предложений Панагиотиса, следующий пример - лучший, который я мог придумать:
void DoSomethingLongRunningOnSql(CancellationToken token)
{
// Avoid getting a connection from the pool if already cancelled.
// This will ensure fast cancellation in the case that
// connection pool is full and .Open() will hang.
token.ThrowIfCancellationRequested();
using (var conn = new SqlConnection("..."))
{
// It may in rare cases take some time to get a connection
// from the connection pool, e.g. i max pool size has been reached
conn.Open();
// Throw if cancelled as close to the actual execution to lower
// the risk of having the cancelation token canceled just before
// executing the query, resulting in the query not being cancelled.
token.ThrowIfCancellationRequested();
var cmd = new SqlCommand("Some long running query", conn);
// Support for cancellation
token.Register(() => cmd.Cancel());
// PROBLEM: If the other thread happened to call cancel at this,
// specific time, the query will not be cancelled and this call
// will hang until the query is done.
// Execute the sql command
cmd.ExecuteNonQuery();
}
}
Кто-нибудь знает, может ли это быть сделано на 100% безопасным способом или я должен просто полагаться на тот факт, что очень редко может произойти, чтобы отмена была вызвана в проблемное время c?