C # Задача была отменена - PullRequest
0 голосов
/ 16 мая 2018

Я написал статический класс, который проверяет подключение пользователя к Интернету и вызывает событие, если изменяется их состояние подключения:

class InternetConnectionMonitor
{

    public static EventHandler<EventArgs<bool>> StatusChanged;

    private static bool isCancelled;
    private static bool isConnected;

    private static bool IsConnected
    {
        get
        {
            return isConnected;
        }
        set
        {
            if (isConnected != value)
            {
                StatusChanged(null, new EventArgs<bool>(value));
            }
            isConnected = value;
        }
    }

    public static async void Start(TimeSpan interval)
    {
        //TODO Use a 1st party webpage for connectivity testing.
        using (var client = new HttpClient())
        {
            client.Timeout = TimeSpan.FromSeconds(2);
            while (!isCancelled)
            {
                try
                {
                    await client.GetAsync("http://example.com");
                    IsConnected = true;
                }
                catch (Exception)
                {
                    IsConnected = false;
                }
                await Task.Delay(interval);
            }
        }
    }

    public static void Stop()
    {
        isCancelled = true;
    }
}

Однако этот класс работает замечательно, когда выполняет некоторую другую обработку с использованиемПоток данных TPL в моем приложении, в цикле while метода Start () возникает исключение, говорящее о том, что задача была отменена.Причина, по которой я пишу здесь, заключается в том, что я никогда не отменяю никаких задач.

Вот обработка, которую я делаю.Исключение отмененной задачи возникает в InternetConnectionMonitor после завершения QueueTests, хотя QueueTests вообще не ссылается на InternetConnectionMonitor.

Если я не вызываю validateProxies (), исключение никогда не вызывается.

private async void validateProxies(IEnumerable<Proxy> proxies)
{
    validateProxiesButton.Enabled = false;
    cancelValidatingProxiesButton.Enabled = true;
    addProxiesButton.Enabled = false;
    removeProxiesButton.Enabled = false;
    proxyTester = new ProxyTester();
    await proxyTester.QueueTests(proxies, judges);
    validateProxiesButton.Enabled = true;
    cancelValidatingProxiesButton.Enabled = false;
    addProxiesButton.Enabled = true;
    removeProxiesButton.Enabled = true;
    MessageBox.Show("Complete!");
}

public class ProxyTester
{

    private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();

    public async Task QueueTests(IEnumerable<Proxy> proxies, IEnumerable<ProxyJudge> judges, int maxConcurrency = 100)
    {
        var testProxies = new ActionBlock<(Proxy proxy, IProxyTest test)>((tup) =>
        {
            tup.proxy.Status = ProxyStatus.Testing;
            tup.proxy.Status = tup.proxy.TestValidity(tup.test);
        }, new ExecutionDataflowBlockOptions { CancellationToken = pcts.Token.CancellationToken, MaxDegreeOfParallelism = maxConcurrency });

        //Set each proxies status to Queued, and post to the dataflow block.
        foreach (var proxy in proxies)
        {
            proxy.Status = ProxyStatus.Queued;
            await testProxies.SendAsync((proxy, judges.GetRandomItem()));
        }

        testProxies.Complete();

        try
        {
            await testProxies.Completion;
        }
        catch (Exception)
        {

        }
    }

    public void Cancel()
    {
        pcts.Cancel();
    }

}

Запуск InternetConnectionMonitor (запрошено JleruOHeP в комментариях)

public proxyTesterView()
{
    InitializeComponent();

    InternetConnectionMonitor.StatusChanged += InternetConnectionMonitor_StatusChanged;
    InternetConnectionMonitor.Start(TimeSpan.FromSeconds(1));
}

private void InternetConnectionMonitor_StatusChanged(object sender, EventArgs<bool> e)
{
    if (e.Value == true)
    {
        MessageBox.Show("Online");
    }
    else
    {
        MessageBox.Show("Offline");
    }
}

1 Ответ

0 голосов
/ 16 мая 2018

Решил свой вопрос и хотел поделиться своим решением. После некоторых размышлений у меня возникло ощущение, что потоки потоков пула истощаются при вызове QueueTests из-за высокой степени параллелизма по умолчанию (100). Это исчерпание пула потоков, по-видимому, имеет непреднамеренные побочные эффекты при вызове client.GetAsync в методе Start () в InternetConnectionMonitor, что приводит к неправильному срабатыванию тайм-аута запроса, в результате чего возникает исключение TaskCancelledException.

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

public static void Start()
{
    //TODO Use a 1st party webpage for connectivity testing.
    var t = new Thread(() =>
    {
        while (!isCancelled)
        {
            try
            {
                var req = HttpWebRequest.Create("http://example.com");
                req.Timeout = 1000;
                using (var resp = req.GetResponse())
                {
                    resp.Close();
                }
                IsConnected = true;
            }
            catch (Exception ex)
            {
                IsConnected = false;
            }
            Console.WriteLine(IsConnected);
            Thread.Sleep(1000);
        }
    });
    t.Start();
}
...