代码之家  ›  专栏  ›  技术社区  ›  spraff

在这种读写器情况下,是否需要检查条件变量虚假唤醒?

  •  0
  • spraff  · 技术社区  · 6 年前

    正如我所理解的条件变量,您通常需要检查虚假唤醒。例如,一个工作线程可能在条件变量通知时被唤醒,而实际上没有一个作业准备就绪。

    所以我们这样做:

     condition_variable .wait (lock, [&] () {return jobs.size() > 0;});
     execute_job (jobs.pop());
    

    好吧,但现在我在我的 execute_job 功能。我有第二个条件变量,它提供了对其他读线程的相当有计划的访问

     void execute_job (job & j)
     {
         current_job = & j;
    
         while (! j.finished ())
         {
             std::unique_lock <std::mutex> lock (reader_mutex);
    
             j.do_some_of_it();
    
             reader_condition.notify_one ();
             reader_condition.wait (lock);
         }
    
         current_job = nullptr;
     }
    

    读取器线程偶尔会(预计不会等待很长时间)

     void inspect_current_job ()
     {
          std::unique_lock <std::mutex> lock (reader_mutex);
    
          if (current_job)
              inspect (current_job);
    
          reader_condition.notify_one ();
     }
    

    此代码是否安全且正确,特别是考虑到我没有检查是否存在虚假唤醒 reader_mutex ?

    1 回复  |  直到 6 年前
        1
  •  0
  •   David Schwartz    6 年前

    不要在设计代码时让互斥锁在所有或大部分时间都被保存。这就是导致你的公平问题的原因。

    听起来你想要一个给一个线程优先级的锁,这样如果一个优先级线程正在等待锁,一个非优先级线程就会停止。做这项工作的线程应该使用非优先级锁定功能,这样任何等待的读卡器都会停止它。

    class prio_lock
    {
        private:
    
        std::mutex m;
        std::condition_variable cv;
        int locked = 0;
        int waiting_priority = 0;
    
        public:
    
        void lock(bool priority)
        {
            std::unique_lock<std::mutex> lk(m);
    
            // wait for all prior priority locks
            while (waiting_priority > 0)
                cv.wait(lk);
    
            if (priority)
                ++waiting_priority;
    
            // wait for lock to be unlocked
            while (locked != 0)
                cv.wait(lk);
    
            if (priority)
                --waiting_priority;
    
            // take the lock
            locked = 1;
        }
    
        void unlock()
        {
            std::unique_lock<std::mutex> lk(m);
            locked = 0;
            cv.notify_all();
        }
    };
    

    请注意,即使非优先级线程持有锁,优先级线程也必须等到当前锁持有者释放锁后才能前进。这是你设计的结果,我强烈怀疑,这是不好的。线程不应该持有其他线程在做大量实际工作时可能需要的锁,而您的设计中需要的任何东西都应该重新考虑。

    我不知道你的完整的外部设计,但是如果读线程只需要访问作业状态,那么看起来写线程应该能够在没有访问作业状态的情况下完成大部分真正的工作,并且应该只在更改该状态时持有锁,而不是在做真正的工作时。