You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Task多线程在Apple M1 Mac上失效问题求助

问题:C# Task在Apple M1 Mac上无法正常运行,Windows环境正常

在Windows开发的控制台应用,切换到Apple M1 Mac设备后,基于Task实现的多线程完全无法运行,但在Windows上正常。不想重写为Thread(耗时且资源开销大),寻求简便解决办法。

相关代码

public void Run()
{
    IPAddress localAddr = IPAddress.Parse(adress);
    server = new TcpListener(localAddr, port);
    server.Start();
    wait = Task.Run(() => WaitingToConnection());
    read = Task.Run(() => ReadAsync());
    ConsoleSend = Task.Run(() => ConsoleSendAsync());
}

public void Stop()
{
    work = false;
    wait.Wait();
    read.Wait();
    ConsoleSend.Wait();
    wait.Dispose();
    read.Dispose();
    ConsoleSend.Dispose(); 
    foreach (TcpClient client in clients)
    {
        Send("!bye", client);
        client.Close();
    }
    clients.Clear();
}


public async Task WaitingToConnection()
{
    Task<TcpClient>? x = null;
    TcpClient client;
    int i = 0;
    while (work)
    {
        Console.WriteLine("жду"+i.ToString());//Here 103/0/1
        i++;
        if (x == null)
        {
            x = Task.Run(() => server.AcceptTcpClientAsync());
        }
        if (x.IsCompleted)
        {
            client = x.Result;
            Console.WriteLine("Подключен клиент. " + ((IPEndPoint)client.Client.RemoteEndPoint).Port);
            clients.Add(client);
            x = null;
        }

    }
}

补充说明

wait.Wait()的断点未触发,但WaitingToConnection循环会输出103、0或1后无响应。


解决方案

1. 修复异步逻辑错误

你的WaitingToConnection标记为async但未使用await,手动轮询Task.IsCompleted会导致CPU空转,在M1的ARM架构下极易触发线程调度异常。正确写法应直接await异步方法:

public async Task WaitingToConnection()
{
    int i = 0;
    while (work)
    {
        Console.WriteLine("жду"+i.ToString());
        i++;
        try
        {
            // 直接await原生异步方法,无需额外包装Task.Run
            var client = await server.AcceptTcpClientAsync();
            Console.WriteLine("Подключен клиент. " + ((IPEndPoint)client.Client.RemoteEndPoint).Port);
            lock(_clientsLock)
            {
                clients.Add(client);
            }
        }
        catch (ObjectDisposedException)
        {
            // 服务器停止时触发异常,直接退出循环
            break;
        }
    }
}

2. 修正Task启动方式

AcceptTcpClientAsync本身就是异步方法,无需用Task.Run包装,直接调用即可返回Task:

public void Run()
{
    IPAddress localAddr = IPAddress.Parse(adress);
    server = new TcpListener(localAddr, port);
    server.Start();
    // 直接调用async方法获取任务
    wait = WaitingToConnection();
    read = ReadAsync();
    ConsoleSend = ConsoleSendAsync();
}

3. 优化Stop方法的资源释放

先停止TcpListener触发异步方法退出,避免Wait()导致的死锁:

public void Stop()
{
    work = false;
    // 先停止服务器,让AcceptTcpClientAsync立即终止
    server.Stop();
    
    // 同步等待所有任务完成
    Task.WaitAll(wait, read, ConsoleSend);
    
    wait.Dispose();
    read.Dispose();
    ConsoleSend.Dispose(); 
    
    lock(_clientsLock)
    {
        foreach (TcpClient client in clients.ToList())
        {
            Send("!bye", client);
            client.Close();
        }
        clients.Clear();
    }
}

4. 解决线程安全问题

clients集合在多线程环境下读写需要加锁,避免ARM架构下的线程竞争异常:

// 新增锁对象
private readonly object _clientsLock = new object();

// 添加客户端时加锁
lock(_clientsLock)
{
    clients.Add(client);
}

// 遍历/清空客户端时加锁
lock(_clientsLock)
{
    foreach (TcpClient client in clients.ToList())
    {
        Send("!bye", client);
        client.Close();
    }
    clients.Clear();
}

内容的提问来源于stack exchange,提问作者AnorakWatts

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 16:25:37