等待其中一项任务成功完成

问题描述 投票:0回答:1

我有一个IP发现方法,我用

TcpClient
测试每个IP地址,当任何IP成功连接时,我在内存中设置
WebServerIp
,那就是在我的世界中任务成功完成的时候。有没有办法在我的代码中实现它?或者当任务“成功”时某种取消标记。

这是我的代码:

public async Task<bool> DiscoverDeviceAsync()
{
    var ips = GeneralService.GetIPAddress();
    PhoneIp = string.Join(",", ips.Select(x => x.ToString()));

    await Task.Delay(1000);

    var tasks = new List<Task>();

    foreach (IPAddress ip in ips)
    {
        byte[] ipBytes = ip.GetAddressBytes();

        for (int i = 0; i <= 254; i++)
        {
            ipBytes[3] = (byte)i;
            IPAddress currentIPAddress = new(ipBytes);
            tasks.Add(ScanIPAddress(currentIPAddress, 9431));
        }
    }

    await Task.WhenAny(tasks);

    return WebServerIp != "";
}

async Task ScanIPAddress(IPAddress ipAddress, int port)
{
    try
    {
        using TcpClient tcpClient = new()
        {
            SendTimeout = 100,
            ReceiveTimeout = 100,
        };

        await tcpClient.ConnectAsync(ipAddress, port);

        WebServerIp = ipAddress.ToString();
    }
    catch
    {
        throw new Exception($"No device found at address: {ipAddress}");
    }
}
c# .net multithreading task
1个回答
1
投票

您需要的是一种在工作完成时向主线程和其他线程发出信号的方法。

为此,您可以将

EventWaitHandle
CancellationToken

结合使用

首先我们创建句柄和取消令牌:

 var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
 var cts = new CancellationTokenSource();

将它们传递给您的方法:

tasks.Add(ScanIPAddress(currentIPAddress, 9431, waitHandle, cts.Token));

然后在方法中设置

WaitHandle
如果连接成功,还要检查取消令牌:

async Task ScanIPAddress(IPAddress ipAddress, int port, EventWaitHandle waitHandle, CancellationToken cancellationToken)
{
    try
    {
        if (cancellationToken.IsCancellationRequested)
        {
            return;
        }
        
        using TcpClient tcpClient = new()
        {
            SendTimeout = 100,
            ReceiveTimeout = 100,
        };

        await tcpClient.ConnectAsync(ipAddress, port, cancellationToken);

        waitHandle.Set();
        WebServerIp = ipAddress.ToString();
    }
    catch
    {
        throw new Exception($"No device found at address: {ipAddress}");
    }
}

此后您可以使用

WaitOne
EventHandle
方法等待标志被设置。这可能意味着以下两种情况之一:其中一项操作成功,或者全部失败:

// Set wait handle after all tasks are finished, so it doesn't wait forever if none of them are successful
// no await here is intentional as we don't wanna wait for all tasks to complete here.
Task.WhenAll(tasks).ContinueWith(_ => waitHandle.Set());
    
waitHandle.WaitOne();

cts.Cancel();

return WebServerIp != "";
© www.soinside.com 2019 - 2024. All rights reserved.