[英]I have a thread.pool and how can i make Main Thread wait until all task are completed?
[英]How can I make sure my task is aware of a flag set on the main thread?
我正在使用 Unity 游戏引擎进行一些联网,我想使用内置语言功能而不是依赖第三方资产或 Unity API。 我想出了这个组件,它附加到一个游戏对象。 当游戏 object 启用时,它应该将 UDP 数据包发送到指定的目的地。
那部分有效。 我遇到的麻烦是这个sending
标志:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using UnityEngine;
namespace UdpTest
{
public class DummySender : MonoBehaviour
{
public string destinationAddress = "127.0.0.1";
public int port = 55555;
UdpClient client;
bool sending;
IPEndPoint endpoint;
private void Awake()
{
client = new UdpClient();
try
{
endpoint = new IPEndPoint(IPAddress.Parse(destinationAddress), port);
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);
client.Connect(endpoint);
}
catch (Exception e)
{
Debug.LogError("Couldn't set up dummy sender: " + e.Message, gameObject);
gameObject.SetActive(false);
}
}
private void OnEnable()
{
sending = true;
new Task(() =>
{
try
{
Debug.Log("Ready to send");
while (sending)
{
var bytes = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.Millisecond.ToString() + "\n");
client.Send(bytes, bytes.Length);
}
}
catch (Exception e)
{
Debug.LogError("Dummy send failed: " + e.Message);
}
}).Start();
}
private void OnDisable()
{
sending = false;
}
}
}
我遇到的问题是,一旦带有循环的任务正在运行,我就无法让它停止。
我的计划是通过将sending
标志设置为 false 来使其在组件被禁用时停止。 我意识到将标志设置为 false 发生在不同的线程上。 我的期望是,是的,循环可能会在sending
标志设置为 false 和访问其值的任务之间运行几次,但这对我的目的来说很好。
然而,实际发生的是任务似乎从未意识到sending
的值已经改变。 它仍然是true
的,循环无限期地运行,并且我的接收器在我终止程序之前不会停止接收数据包。
为什么是这样? 我对低级任务/线程有点陌生,但我知道不能保证工作任务会立即意识到更改。 我本来希望它最终会更新。 但就我而言,虽然我可以验证主线程上的sending
标志已设置为 false,但任务中的循环永远不会停止。
如果我不得不猜测,这似乎与您在复制值并更改原始值时遇到的错误相同(即按引用/按值错误)。 该任务是否实际上有一个sending
副本而不是对 class 实例字段的引用? 还是我错过了其他东西?
我知道还有其他策略可以实现 UDP 通信,例如使用Async
变体,但是为了学习,我想知道我在这里做错了什么以及如何在不完全改变策略的情况下修复它。
我曾经对相同的任务有同样的问题。 使用 CancellationTokenSource 修复它。 方法如下:
var source = new CancellationTokenSource ();
Task.Factory.StartNew ( obj => YourMethod ( (CancellationToken) obj ), source.Token, source.Token );
public void YourMethod ( CancellationToken token )
{
while (!token.IsCancellationRequested)
;// insert ur code
}
并取消它,将源变量全局存储在某个地方,然后在想要取消调用时:
source.Cancel ();
你也有这条线:
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);
这是完全没用的,因为 UDP 定义为非接触式协议,所以.Connect 和.Send 不会阻塞线程。 All.Connect 所做的就是在调用时设置默认的 IPEndPoint。在不提供目标 IPEndPoint 的情况下发送
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.