【问题标题】:Synchronization Issue for a Queue队列的同步问题
【发布时间】:2012-09-22 14:23:09
【问题描述】:

我有以下代码可以访问一个 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(),并且当第一个线程再次恢复时它将继续调用result.sendResult(),并使用结果的线程本地值(该线程在被阻塞之前从队列中获得)。静态计数变量在那里,以便我可以使用睡眠模拟随机线程的长时间处理,因为正如我在上面解释的那样sendResult() 可能需要很长时间才能进行某些调用。

我用这段代码运行了一组测试,到目前为止一切正常。但是我只是想在这里问这个问题,以便如果这种方法有任何问题,我可以得到你们的所有想法。我不是并发编程方面的专家。如果有更好、更高效、更简洁的方法来做到这一点,也许不是在队列级别而是在单个数据项级别的并发,请告诉我。

【问题讨论】:

  • 有一个很好的理由将empty() 签入同步块。情况:队列中的一项,两个线程进入sendClientReply。两者都通过了empty() 检查,一个进入同步块,清空队列,然后继续前进。现在,当第二个线程进入块时,您可以通过在空队列上调用 .front() 来获得未定义的行为。
  • 我明白了。 +1 的答案和解释!

标签: c++ concurrency synchronization queue


【解决方案1】:

总的来说,您的方法是正确的,但我想注意两点:

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

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

更新: 修复很简单:

    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();
    }

【讨论】:

  • +1。是的,在这种情况下它似乎没有问题,但通常为了线程安全,我完全同意你的观点。
  • 我更新了答案以使其真正线程安全。是的,这不是一个大问题,但可能会发生 2 个线程同时休眠,而只有一个线程应该休眠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 2017-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多