关于.net:线程从另一个线程结束检查

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,则使用BlockingCollection<T>

    会非常容易。

    编辑:如果不需要按特定顺序处理数据包,则可以为每个数据包启动一个新的线程池工作项:

    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方面可能更好。