Boost Shared_lock/Unique_lock如何赋予写线程优先级?
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_mutexprioritizes readers by design. If a writer is waiting, new readers can still acquire shared locks, leading to potential writer starvation. - Unsynchronized Flag: Your
frameOkvariable 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:
frameOkis 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

