Thread End checking from another Thread
我有一个通过TcpClient从端口读取数据的类。我创建了2个线程。
1线程连续读取字节,一旦获得正确的数据包,便将该数据包添加到队列中并启动第二线程,然后第二线程从该队列中读取数据包并进行处理。
数据包处理应按顺序进行。因此,每次读取线程在Queue中添加数据包时,都会检查该处理线程是否正在运行。如果不是,那么它将再次启动该线程。这是因为我们不希望多个数据包处理线程同时运行。
现在我的问题实际上与该检查部分有关。我所做的就是,在我的类上添加了一个简单的bool变量。当我进入数据包处理线程时,将bool设置为true。当数据包读取线程检查此bool变量时,如果该变量为true,则它知道处理线程正在运行。并且当数据包处理线程到达末尾时,它将设置为bool = false。
这是正确的方法吗?还是这种方法容易出现竞争状况?
谢谢。
更新(一点细节):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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。
或者
*)应该以某种方式阻止它,直到没有收到另一个数据包为止。
您可能想为此使用BlockingCollection < T >类。您的处理线程将阻止等待下一个项目入队。
一些建议阅读:C#中的线程。
您肯定有一个竞赛条件,没有比描述的更多的锁定。如果两个数据包连续快速进入,您可能会看到该标志两次为假,并启动了两个不同的线程。您可以通过使读取线程在启动线程时将标志设置为false来避免这种情况-因此该标志表示"线程正在运行或正在启动"。
目前尚不清楚为什么您仍然需要保持启动线程-为什么当队列为空时,为什么不只有一个处理线程阻塞等待新数据包呢?如果您使用的是.NET 4,则使用
会非常容易。
编辑:如果不需要按特定顺序处理数据包,则可以为每个数据包启动一个新的线程池工作项:
1 2 3 4 5 6 7 8 9 | ThreadPool.QueueUserWorkItem(ProcessPacket, packet); ... private void ProcessPacket(object state) { Packet packet = (Packet) state; ... } |
首先,您应该避免使用"共享资源",这意味着在多个线程上使用的Data,Properties,..。
如果使用它们,则应同步它们(例如ReaderWriterLockSlim)
此外,还有一些名为TPL的扩展类,这些扩展类使使用线程变得更容易。有关此链接,请参见eaxample。
如果您使用TPL,并且在那里使用Task Class,则可以使用例如Wait Method完成任务。
->任务myTask = Task.Factory.StartNew(()=> Foo());
1 | myTask.Wait(); |
在进行多线程处理时,我总是建议使用TPL或至少使用Threadpool。
您还可以考虑使用RX,它在Thread和linq上具有某种统一的编程模型。
另一种设计是改为使用等待句柄,并等待直到其发出信号,然后再调用处理-在CPU方面可能更好。