You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost Shared_lock/Unique_lock如何赋予写线程优先级?

实现Boost Thread的写优先读写锁

Absolutely, you can implement the write-preferred behavior you want! The core issue with your current code is that boost::shared_mutex defaults to reader-preferred logic — once readers start grabbing shared locks, waiting writers get stuck until all active readers release their locks, and even new readers can cut ahead of writers. To let writers jump the queue when they're ready, we need to build a write-priority shared lock.


Why Your Current Setup Fails

  • Reader Bias: boost::shared_mutex prioritizes readers by design. If a writer is waiting, new readers can still acquire shared locks, leading to potential writer starvation.
  • Unsynchronized Flag: Your frameOk variable is accessed without any locking, which creates a data race (this needs fixing to avoid undefined behavior).

Solution: Build a Write-Priority Shared Lock

We can wrap boost::shared_mutex with condition variables to track waiting writers, ensuring that once a writer requests the lock, no new readers can access the resource until the writer finishes. Here's the adjusted code:

Step 1: Define the Write-Priority Lock Class

#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <atomic>

class WritePrioritySharedLock {
private:
    boost::shared_mutex m_mutex;
    boost::condition_variable_any m_writerCond;
    std::atomic<int> m_waitingWriters{0};
    std::atomic<int> m_activeReaders{0};

public:
    // Exclusive write lock
    void lock() {
        m_waitingWriters++;
        m_mutex.lock();
        // Wait until all active readers are done
        while (m_activeReaders > 0) {
            m_writerCond.wait(m_mutex);
        }
        m_waitingWriters--;
    }

    void unlock() {
        m_mutex.unlock();
        m_writerCond.notify_all(); // Wake waiting readers/writers
    }

    // Shared read lock
    void lock_shared() {
        m_mutex.lock_shared();
        // Block if writers are waiting, then re-acquire
        while (m_waitingWriters > 0) {
            m_mutex.unlock_shared();
            m_writerCond.wait(m_mutex);
            m_mutex.lock_shared();
        }
        m_activeReaders++;
    }

    void unlock_shared() {
        m_activeReaders--;
        // Wake a waiting writer if no readers are left
        if (m_activeReaders == 0 && m_waitingWriters > 0) {
            m_writerCond.notify_one();
        }
        m_mutex.unlock_shared();
    }
};

Step 2: Update Your Main Code

Replace your original lock definitions and fix the frameOk data race:

#include <boost/thread.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
#include <sstream>
#include <atomic>

typedef WritePrioritySharedLock Lock;
typedef boost::unique_lock<Lock> WriteLock;
typedef boost::shared_lock<Lock> ReadLock;

Lock frameLock;
cv::Mat currentFrame;
std::atomic<bool> frameOk{false}; // Atomic to avoid data races

void writer() {
    while (true) {
        cv::Mat frame;
        cv::Mat src = cv::imread("C:\\grace_17.0001.jpg");
        cv::resize(src, frame, cv::Size(src.cols / 4, src.rows / 4));
        
        int64 t0 = cv::getTickCount();
        { // Scope to auto-unlock when write is done
            WriteLock w_lock(frameLock);
            frame.copyTo(currentFrame);
            frameOk = true; // Safe atomic write
        }
        int64 t1 = cv::getTickCount();
        double secs = (t1 - t0) / cv::getTickFrequency();
        std::cout << "wait time WRITE: " << secs * 1000 << "ms" << std::endl;
        
        // Simulate real-world write workload (adjust as needed)
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
}

void readerTwo(int wait) {
    while (true) {
        if (frameOk.load()) { // Safe atomic read
            static cv::Mat readframe;
            int64 t0 = cv::getTickCount();
            {
                ReadLock r_lockz(frameLock);
                currentFrame.copyTo(readframe);
            } // Auto-unlock after reading
            int64 t1 = cv::getTickCount();
            double secs = (t1 - t0) / cv::getTickFrequency();
            std::cout << "READ: " << wait << " | Wait time: " << secs * 1000 << "ms" << std::endl;
            
            cv::imshow(std::to_string(wait), readframe);
            cv::waitKey(1);
            std::this_thread::sleep_for(std::chrono::milliseconds(20));
        } else {
            // Wait briefly if no frame is ready yet
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
}

int main() {
    const int readerthreadcount = 50;
    std::vector<boost::thread*> readerthread;
    boost::thread* wThread = new boost::thread(writer);
    
    for (int i = 0; i < readerthreadcount; i++) {
        readerthread.push_back(new boost::thread(readerTwo, i));
    }
    
    wThread->join();
    delete wThread;
    for (auto thread : readerthread) {
        thread->join();
        delete thread;
    }
    
    return 0;
}

How This Works

  • Write Priority: When a writer requests the lock, we increment m_waitingWriters. New readers will check this flag and block until the writer completes.
  • Active Reader Tracking: We count active readers so writers only wait for currently running readers (no new readers can jump in once a writer is waiting).
  • Atomic Safety: frameOk is now an atomic variable, eliminating data races when checking or updating the flag.

With this setup, you'll see your desired execution flow: Writer→reader1→reader2→Writer (when ready)→reader3→reader4.

内容的提问来源于stack exchange,提问作者anti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:53:55