我有一个通过TcpClient从端口读取数据的类。我创建了2个线程。
1线程连续读取字节,一旦获得正确的数据包,它就会在队列中添加该数据包并启动第二个线程,然后从该队列中读取数据包并对其进行处理。
数据包处理应按顺序进行。因此,每当读取线程在队列中添加数据包时,它都会检查处理线程是否正在运行。如果不是,那么它再次启动该线程。这是因为我们不希望同时运行多个数据包处理线程。
现在我的问题实际上与检查部分有关。我所做的是,我在课堂上添加了一个简单的bool变量。当我进入数据包处理线程时,我设置了bool = true。数据包读取线程检查此bool变量,如果为true,则它知道处理线程正在运行。当数据包处理线程最后到达时,它会设置bool = false。
这是正确的方法吗?或者这种方法是否容易出现竞争状态?
感谢。
更新(一点细节):
delegate void PacketProcessDelegate();
PacketProcessDelegate PacketProcess = new PacketProcessDelegate(this.PacketProcessingThread);
PacketReadingThread() {
Packet = GetPacket(); // thread blocks until packet is NOT received
Queue.Synchronized(this.Queue).Enque(Packet);
if (!this.IsProcessing)
this.PacketProcess.BeginInvoke(null, null);
}
PacketProcessingThread() {
this.IsProcessing=true;
while(true) {
Queue syncQueue;
syncQueueu = Queue.Synchronized(this.Queue);
if(syncQueueu.Count > 0)
//packet extraction and processing code here
else
break;
}
this.IsProcessing=false;
}
目标:
数据包处理线程为
*)应该终止并且应该重新启动,但是应该使用ThreadPool以防止每次都创建新线程。这就是我使用BeginInvoke的原因
OR
*)它应该以某种方式被阻止,直到没有收到另一个数据包。
答案 0 :(得分:2)
你肯定有一个竞争条件,没有任何锁定比描述。如果两个数据包快速连续进入,您可能会看到该标志为假两次并启动两个不同的线程。您可以通过使读取线程在启动线程时将标志设置为false来避免这种情况 - 因此该标志表示“线程正在运行或正在启动”。
目前还不清楚为什么你还需要继续启动线程 - 为什么不只是让一个处理线程在队列为空时阻塞等待新数据包?如果您使用的是.NET 4,那么使用BlockingCollection<T>
非常容易。
编辑:如果您不需要按特定顺序处理数据包,则可以为每个数据包启动一个新的线程池工作项:
ThreadPool.QueueUserWorkItem(ProcessPacket, packet);
...
private void ProcessPacket(object state)
{
Packet packet = (Packet) state;
...
}
答案 1 :(得分:2)
您可能需要考虑使用BlockingCollection<T>类。您的处理线程将阻止等待下一个项目入队。
有人建议阅读:Threading in C#。
答案 2 :(得分:0)
另一种设计是使用wait handle代替并等到它在调用处理之前发出信号 - 可能在CPU方面更好。
答案 3 :(得分:0)
首先,你应该避免使用“共享Resssources”这意味着,数据,属性,...在多个线程上使用。
如果你使用它们,你应该同步它们(s。ReaderWriterLockSlim)
还有一些名为TPL的扩展类使得更容易使用线程。请参阅此示例link。
如果您使用TPL,那么您可以使用Task Class作为完成任务的等待方法。
- &GT;任务myTask = Task.Factory.StartNew(()=&gt; Foo());
myTask.Wait();
我总是使用TPL或至少使用Threadpool进行多线程处理。
你也可以考虑使用RX,它在Thread和linq上有某种统一的编程模型