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
相关产品推荐
相关产品推荐

