Извините, что не отвечаю на ваш вопрос - а почему не используете 
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
});
В общем много чего можно сделать, проще всего не изобретать велосипед и взять готовое решение.