Итак, я создаю менеджер загрузок, и я разработал каждый бит специально, чтобы его можно было закрыть в любую секунду, не давая ему времени на очистку. Однако я не могу найти способ убить мои потоки загрузчика. Я пробовал использовать Thread.Abort (на самом деле, это мой способ дать им время на очистку: они ловят ThreadAbortException и обрабатывают его сами), но, как вы уже догадались, это бесполезно. Я бы использовал флаг или что-то в этом роде, но когда поток ожидает завершения сетевой операции, он почти полностью блокируется. Есть идеи, как хотя бы прервать работу сети, чтобы я мог выключиться, не дожидаясь заметного количества времени?

Вот соответствующий фрагмент кода:

try
{
    Request.AddRange(StartPosition, EndPosition);
    Owner.SetDefaultRequestParameters(Request);

    Response = Request.GetResponse() as HttpWebResponse;
    ResponseStream = Response.GetResponseStream();

    var Buffer = new Byte[Downloader.BUFFER_SIZE];

    while (true)
    {
        Paused.Wait();

        if (bStopRequested)
            break;

        int Count = ResponseStream.Read(Buffer, 0, Buffer.Length); //gets stuck here
        if (Count == 0)
            break;

        MemoryStream.Write(Buffer, 0, Count);
        Downloaded += Count;
        CurrentStreak += Count;

        if (StartPosition + Downloaded >= EndPosition)
            break;

        if (MemoryStream.Capacity - CurrentStreak < Buffer.Length)
        {
            Owner.WriteToFile(MemoryStream, StartPosition + Downloaded - CurrentStreak, CurrentStreak);
            MemoryStream.Seek(0, SeekOrigin.Begin);
            CurrentStreak = 0;
        }
    }
}
catch (ThreadAbortException)
{
    try
    {
        Response.Close();
    }
    catch { }

    return; //fastest way I have found to shut the thread down, yet
}

РЕДАКТИРОВАТЬ: Итак, вот как я это сделал:

if (Request != null)
    Request.Abort();
if (Response != null)
    Response.Close();
ExecutionThread.Abort();

При этом независимо от того, где поток застрял (получение ответа или чтение из потока ответов), он будет отменен и немедленно остановится.

0
Arshia001 29 Дек 2013 в 01:08

2 ответа

Лучший ответ

Вы можете избавиться от ResponseStream, а затем поймать ObjectDisposedException.

Хотя это может сработать, я предлагаю вам разработать свое приложение с использованием CancellationToken, чтобы оно могло изящно закрываться, а не резко прерывать потоки. Вы также можете рассмотреть возможность использования async-await, чтобы сделать ваше приложение более масштабируемым и неблокирующим.

2
i3arnon 28 Дек 2013 в 21:18

Не уверен, что делает базовый сокет, но если все не удается, вы можете напрямую привязаться к сокету в неблокирующем режиме и использовать метод Socket.BeginReceive, который вызовет ваш обратный вызов, когда данные будут получены. Если вы действительно хотите отменить текущую операцию, вы можете просто вызвать close сокет и все. См. MSDN

Асинхронная операция BeginReceive должна быть завершена путем вызова метода EndReceive. Обычно метод вызывается делегатом обратного вызова.

Этот метод не блокируется, пока операция не будет завершена. Чтобы заблокировать, пока операция не будет завершена, используйте одну из перегрузок метода приема.

Чтобы отменить ожидающий BeginReceive, вызовите метод Close .

Вы должны проверить, можете ли вы добраться до нижележащего сокета, и попытаться его закрыть.

1
Alois Kraus 28 Дек 2013 в 22:37