Извините, что не отвечаю на ваш вопрос - а почему не используете
https://github.com/XamlAnimatedGif/XamlAnimatedGif ?
По делу - если мне не изменяет память, нет простого способа прибить Task, для этого нужно использовать CancellationTokenSource, что вы и делаете в приведенном примере. Если отмена через CancellationTokenSource не срабатывает по какой-то причине - поставьте брейкпоинты или навтыкайте логов через каждую строку, найдите проблемное место, и уже исходя из этой информации решайте.
Исходя из вашей проблемы, для начала после отмены можно просто подождать завершения таска:
// Метод в котором останавливаете анимацию
cancellationTokenSource3.Cancel();
await th_Image3;
или
// Метод в котором останавливаете анимацию
cancellationTokenSource3.Cancel();
th_Image3.GetAwaiter().GetResult();
Так вы по-крайней мере должны избавиться от наложения тасков друг на друга.
Далее, таски можно чуть-чуть проще запускать, вот так:
th_Image3 = Task.Run(() =>
{
// ......
});
Кроме того, если вам действительно нужно, чтобы код внутри Task.Run всегда выполнялся только в единственном экземпляре - это значит, что вам нужна критическая секция. В данном случае можно сделать при помощи семафоров:
// ......................
Semaphore _semaphore = new Semaphore(1, 1);
// ......................
th_Image3 = Task.Run(() =>
{
_semaphore.WaitOne();
try
{
// Показ GIF
}
finally
{
_semaphore.Release();
}
});
Или же можно использовать метод ContinueWith, чтобы организовать какое-то подобие очереди задач:
// .................................................
Task th_Image3 = Task.FromResult(0);
// .................................................
th_Image3 = th_Image3.ContinueWith(() =>
{
// Отображение GIF
});
В общем много чего можно сделать, проще всего не изобретать велосипед и взять готовое решение.