110,535
社区成员
发帖
与我相关
我的任务
分享
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;
byte[] buf = new byte[n];
comm.Read(buf, 0, n);
builder.Clear();
this.Invoke((EventHandler)(delegate
{
if (checkBoxHexView.Checked)
{
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
builder.Append(Encoding.ASCII.GetString(buf));
buffer = (Encoding.ASCII.GetString(buf)).ToString();
}
}));
}
public class TestGateway
{
public List<byte> buffer = new List<byte>();
public void Received(byte[] data)
{
lock (buffer)
{
buffer.AddRange(data);
命令处理();
}
}
private void 命令处理()
{
begin:
var pos = buffer.IndexOf(0x0a);
if (pos < 0)
return;
if (Execute != null)
{
var command = Encoding.UTF8.GetString(buffer.ToArray(), 0, pos);
ThreadPool.QueueUserWorkItem(h => Execute(command));
}
buffer.RemoveRange(0, pos + 1);
goto begin;
}
public event Action<string> Execute;
}
这是封装一个通用的 gateway,用来处理消息接收。当你以类似这样的代码 public TestGateway gateway = new TestGateway();
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;
byte[] buf = new byte[n];
comm.Read(buf, 0, n);
gateway.Received(buf);
}
调用它的时候, comm_DataReceived 事件处理过程本身就会是在子线程中被触发,因此执行到 gateway.Received 方法中的关键代码时,进入 lock 临界区,保证只有一个线程能进入 buffer 数据处理区域。在这个区域中,按照换行(0x0a)作为命令分隔符的信令约定,来判断是否存在一条完整命令。如果存在,就把完整的命令从 buffer 中取出来,并且异步(使用系统线程池)触发 Execute 事件,凡是捕获了这个事件通知的客户程序都能收到通知。
这里,只有把数据放入buffer、并且判断完整的命令部分,是在 lock 中执行的,是阻塞了所有(由comm_DataReceived 所在的)子线程的。然后当实际发现了每一条完整的命令,就异步多线程地触发 Execute 事件了,各个业务处理过程本身又是并发多线程地去处理业务。
因此 I/O 并不被业务处理过程所阻塞。private void Comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;
byte[] buf = new byte[n];
comm.Read(buf, 0, n);
builder.Clear();
this.Invoke((EventHandler)(delegate
{
builder.Append(Encoding.ASCII.GetString(buf));
buffer = (Encoding.ASCII.GetString(buf)).ToString();
queue.Enqueue(buffer);
Thread t = new Thread(() => MyThread(buffer));
t.Start();
}));
}
void MyThread(string str)
{
while (true)
{
if (queue.Count > 0)
{
MessageBox.Show(buffer);
queue.Dequeue();
}
else
{
Thread.Sleep(100);
}
}
}
1,如果我把线程开在DataReceived里面,能正确显示收到的buffer,但是如果在 void MyThread(string str)设置断点,进到断点后,按F10或者F11,代码都不能再执行下去了,这是什么原因呢?
2,如果我在 Form1_Load开线程,不能正确显示收到的buffer:private void Form1_Load(object sender, EventArgs e)
{
Thread t = new Thread(() => MyThread(buffer));//buffer为全局变量
t.Start();
}
ps:我还有一个button,发送指令的.
//就是在方法外部
static Queue<string> queue= new Queue<string> ();//看你实际这个类是怎么用的,如果全程只会new一个,那么这里也可以不用Static
//你的DataReceived方法里面将接收到的内容放入队列末尾quque.Enqueue
//在另开一个线程,如果是frame 4之前的就用Thread或者ThreadPool,4之后的话可以Task,这个线程就是
while(true)
{
if(queue.Count>0)
{
queue.Dequeue//也可以用Peek,先处理,处理完了之后才用Dequeue移除
}
else
{
Thread.Sleep(100);//或者也可以用timer定时处理
}
}