c#嵌套线程
nested Threads with c#
嗨,我对一般线程非常陌生。
我正在用 C# 开发类似蓝牙聊天的东西。
主要形式有 2 种可能性
1.更新BT设备列表并连接设备(工作正常)
2.监听连接到自己BT芯片的设备。
用于测试BT功能被禁用。
对于#2,我在加载表单后创建了一个线程。
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
因为监听总是正确的,所以创建并显示了一个新的表单(新的 sendReceiveForm)。
新表单包含另一个线程,该线程在新表单加载后执行
并有一个循环检查是否收到信息。
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
第二种形式的流是来自一个简单的.txt streamReader 的流,具有1 位数字。
第二个线程陷入无限循环(或看起来如此)并且应用程序崩溃。
我不知道问题出在哪里,也不知道如何解决。
//编辑
将方法更新为:
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
但没有区别
//EDIT2
问题是它工作正常,直到启动 2 线程。
如果我评论 2 线程的开头,则创建表单并且似乎工作正常。
我很确定这个子句隐藏了这个问题:
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
删除它,因为它会捕获所有异常并且什么都不做。删除后再次以调试模式运行,您将看到实际错误。看看这里。
该表单可能没有正确创建,因为您的后台线程中充斥着消息,而后台线程总是在一个紧密的无限循环中执行。
为什么不尝试使用"阻塞"流,以便它阻止线程执行,直到通过蓝牙接收到实际数据
所以 Stream.ReadByte() 说:
Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
一旦网络流关闭,它就会保持这种状态。所以溪流说:我关门了。但是你的代码继续循环,得到-1,循环得到-1,循环。你需要做例如:
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
请注意,它修复了代码示例中的第二个问题...它执行 ReadByte 并将值丢弃,然后将下一个字节发送到屏幕。
上面的吉姆米歇尔已经说过了,但你似乎错过了他的答案。 :-)
接受
无论如何,有一个更早的问题......"流"被初始化为什么?假设您正在使用来自 32feet.NET 的 BluetoothListener(它使用相同的模式以及 FCL 的 TcpListener 和 IrDAListener),您需要接受一个新连接。你在某个地方这样做吗?我希望 checkForConnection 这样做:
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}
你的 receiveData 方法很奇怪。
所以它是在非 UI 线程上调用的。假设它读取的字节不是 -1。
调用是必需的,所以它会回调自己。
现在它读取一个字节并得到一个-1(你说文件只有1位)。
现在它永远在循环中旋转。
此外,如果您在 UI 线程上调用该方法并且它读取一个字节,则它必须在输出之前读取另一个字节。
如果您正在查看尚未关闭的网络流,这也可能在第二次调用 stream.ReadByte 时挂起。在流关闭之前,您的代码无法知道已经到达终点。这与文件不同。
你还没有创造出逃避循环的方法。此方法中没有任何内容将 listening 设置为 false。由于它在 UI 线程上旋转,因此您无法按下取消按钮或其他任何东西。
我想你想做的是:
private void MainForm_Load(object sender, EventArgs e)
{
incomingConnectionThread = new Thread(checkForConnection);
incomingConnectionThread.Start();
}
public void checkForConnection()
{
while (listening) //boolean which is always true
{
if (cargui == null)
{
cargui = new sendReceiveForm(null);
cargui.ShowDialog();
}
}
}
private void CarGui_Load(object sender, EventArgs e)
{
thread = new Thread(receiveData);
thread.Start();
}
private void receiveData()
{
while (listening)
{
try
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
catch
{
}
}
}
private void receiveData()
{
while (listening)
{
if (stream.ReadByte() != -1)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new rtfDelegate(receiveData));
}
else
{
rtfReceiveWindow.Text += stream.ReadByte().ToString();
}
}
}
}
catch
{
}
void DataReader_Runner(object state)
{
Stream strm = (Stream)state;
while (true) {
int bi = strm.ReadByte(); // This blocks waiting for data...
if (bi == -1)
break;
byte b = (byte)bi; // Now we know that it is not the special -1 int value
... use the new byte ...
}
}
while (!appQuitting) {
// This blocks waiting for a incoming connection...
var conn = listener.AcceptBluetoothClient();
var strm = conn.GetStream();
ThreadPool.QueueUserWorkItem(DataRead_Runner, strm);
}
private void updateReceived(string s)
{
if (rtfReceiveWindow.InvokeRequired)
{
rtfReceiveWindow.Invoke(new Action(() => updateReceived(s); }));
}
rtfReceiveWindow.Text += s;
}
private void receiveData()
{
while (listening)
{
int recv = stream.ReadByte();
if (recv != -1)
{
updateReceived(recv.ToString());
}
}
}