**关闭。**此题需要debugging details。目前不接受答复。
编辑问题以包括desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
6小时前关闭
截至1小时前,社区正在审查是否重新开放此问题。
Improve this question
我有一个进程,产生2个线程。一个线程从Web Socket读取,另一个线程写入同一个Web套接字。一旦所有东西都初始化并且Web Socket已经连接,主线程就会阻塞它在以下函数中创建的2个线程:
public void BlockUntilThreadsAreDone()
{
if (_incomingThread.IsAlive)
_incomingThread.Join();
if (_outgoingThread.IsAlive)
_outgoingThread.Join();
}
暂时一切正常。但几分钟后,我发现主线程将从这个函数返回。没有抛出任何异常,也没有看到任何异常日志记录。该函数只是因为Thread.Join()
调用返回而返回。
我修改了函数,以等待两个线程在关闭时都会设置的事件,如下所示:
private readonly ManualResetEventSlim _messagingComplete = new(false);
public void BlockUntilThreadsAreDone()
{
if (_incomingThread.IsAlive)
_incomingThread.Join();
Console.WriteLine($"Incoming thread state={_incomingThread.ThreadState}");
if (_outgoingThread.IsAlive)
_outgoingThread.Join();
Console.WriteLine($"Outgoing thread state={_outgoingThread.ThreadState}");
_messagingComplete.Wait(_cancellationToken);
}
线程对象是这样创建的
_incomingMessageThread = new(HandleIncomingMessages) { Name = "Incoming" };
_outgoingMessageThread = new(HandleOutgoingMessages) { Name = "Outgoing" };
private async void HandleIncomingMessages()
try
{
Console.WriteLine("PapiClient HandleIncomingMessages starting");
do
{
try
{
Message? message = await ReceiveIncomingMessageAsync();
// Handle each message asynchronously so we can keep receiving more messages
_ = Task.Run(
() =>
{
HandleIncomingMessage(message);
},
_cancellationToken
);
}
catch (OperationCanceledException)
{
break;
}
catch (Exception ex)
{
Console.WriteLine($"Exception while handling messages: {ex}");
}
} while (!_cancellationToken.IsCancellationRequested && Connected);
}
catch (ObjectDisposedException) { }
finally
{
_messagingComplete.Set();
Console.WriteLine(
$"PapiClient HandleIncomingMessages finishing: cancel={_cancellationToken.IsCancellationRequested}, connected={Connected}"
);
}
}
现在代码按照我的预期工作(即,函数只在我们完成处理后返回)。从技术上讲,这是不一样的,因为一旦第一个线程完成,它就会返回,但这对我的目的来说已经足够接近了。
有趣的是,我看到在进程启动几分钟后,两个线程最终都将记录其状态为ThreadState.Stopped
。但是,线程肯定不会停止,因为我可以告诉进程继续通过Web Socket发送和接收数据,并且没有创建其他线程来使用Web套接字。此外,线程终止时发生的所有正常处理都不会在该点发生。
文档中说Join
“阻塞调用线程,直到这个示例所代表的线程终止。”The documentation还说“线程永远不能离开Stopped状态。”
我很困惑。为什么Thread.Join()
会返回,而一个线程在最肯定没有停止的情况下指示它的状态是Stopped
?
我怀疑这可能与网络和/或Web套接字有关。我运行了一个数据包捕获,在问题发生前几毫秒,WebSocket发送了一个未经请求的PONG消息。未经请求的PONG本身并不是问题,但这些PONG每30秒发送一次,因此在定时器唤醒并发送PONG消息后几毫秒内发生伪Thread.Join()
似乎是不寻常的。
我在.NET core github issues list上找不到这个问题。有什么想法吗
1条答案
按热度按时间hwamh0ep1#
看看你在Github上的代码库(顺便说一下,你的问题应该是独立的),两个函数
HandleOutgoingMessages
和HandleIncomingMessages
被标记为async void
。这意味着一旦它们到达第一个await
,它们就会结束,并将继续发送到线程池。您似乎期望它们所在的线程会以某种方式暂停,并在
await
继续发生时重新启动。事实并非如此。您的线程结束了,线程池将把它捡起来。这本质上是线程和任务之间的混淆。您主要使用任务和异步,我建议您坚持使用,因此使用
Task.Run
来卸载Handle
功能。您需要进行以下更改
删除构造函数中以
_incomingMessageThread =
和_outgoingMessageThread =
开头的行。将
_incomingMessageThread.Start(); _outgoingMessageThread.Start();
行替换为在需要等待线程完成的不同时刻,只需执行
您不需要检查它们是否已完成,在此之后它们将始终完成。
或者