队列的同步问题

时间:2012-09-22 14:23:10

标签: c++ concurrency synchronization queue

我有以下代码来访问c ++队列(responseQueue)并在进行一些处理后发送响应:

void sendRelpyToClient(){    
    if (responseQueue.empty())
       return;

    static int count = 0;
    Result result;

    SYNCHRONIZE() { //start of synchronization (pseudo-code)

       result = responseQueue.front();
       responseQueue.pop();

    } //end of synchronization

    if(count++ % 9 == 0)
    {
        //simulate some processing with a sleep
        sleep for 15 seconds

    }

    result.sendResult();
}

responseQueue包含Result的实例。 sendResult()方法可能需要一些处理时间,因此对于存储在队列中的某些结果,方法返回可能需要相对较长的时间。方法sendRelpyToClient()由多个线程访问,如果result.sendResult()也在SYNCHRONIZED()块中,则由于sendResult()方法而导致的任何其他线程都被阻止需要很长时间才能回来。这就是我选择这种方法的原因。

我的这个实现的逻辑是访问responseQueue的任何线程将首先检查队列是否为空并返回。因为任何访问SYNCHRONIZE()块的线程如果其中只有一个项目就会使队列为空,则不需要将此检查放在SYNCHRONIZE()块内。如果在SYNCHRONIZE()块之后立即(通过线程调度程序)取消正在访问队列的一个线程,则第二个线程将再次获取队列中的下一个项目并调用result.sendResult(),并且第一个线程再次恢复它将继续使用结果的线程本地值(该线程在阻止getiing之前从队列中获取)调用result.sendResult()。静态计数变量就在那里我可以使用sleep模拟随机线程的长处理,因为正如我上面所解释的那样sendResult()可能需要很长时间才能进行一些调用。

我用这段代码运行了一组测试,到目前为止它一直没问题。但我只是想在这里提出这个问题,这样如果这种方法有任何问题,我可以得到你所有人的想法。我不是并发编程方面的专家。如果有一个更好,更有效,更干净的方法来做到这一点,可能并非在队列级别的并发性,而是在个别数据项的级别,请告诉我这些。

1 个答案:

答案 0 :(得分:2)

一般来说,你的方法是正确的,但我想注意两件事:

  1. 正如Xeo已经提出的那样,你应该检查同步块中队列是否为空。

  2. 您有静态变量count,它是全局变量,您可以从多个线程读取/写入它而不进行同步。这不是那么危险,但可能导致算法的错误工作。请记住,增量不是原子操作。当2个线程同时为count计算一个新值时,你可能会遇到这种情况。

  3. UPD: 修复很简单:

        void sendRelpyToClient(){    
            static int count = 0;
            Result result;
    
            bool execute = false;
    
            SYNCHRONIZE() { //start of synchronization (pseudo-code)
                if (responseQueue.empty())
                   return;
               result = responseQueue.front();
               responseQueue.pop();
    
               execute = (count++ % 9 == 0);
            } //end of synchronization
    
            if (execute)
            {
                //simulate some processing with a sleep
                sleep for 15 seconds
            }
            result.sendResult();
        }