关于读锁和写锁最好的一篇文章
来源:互联网 发布:算法设计 下载 编辑:程序博客网 时间:2024/04/29 20:08
Developing threaded software is always a challenge. Breaking a complex application into separate units of execution without compromising its stability requires not only a well-structured design that prevents the developer from accessing unsafe data, but also a good understanding of the concepts, tools, and caveats of multithreaded programming.
- Understanding Mutexes and Semaphores
- Mutually Exclusive Readers
- Fast, but Not Fair
- Fair, but Fairly Limited
- Share and Enjoy
- A Read/Write Mutex Class
- Conclusion
In this article, we will review the problems encountered when implementing a read/write mutex, a synchronization tool for protecting resources that can be accessed for reading and writing. We want to allow multiple threads to have simultaneous read-only access, but as soon as one thread wants to write to the resource, all other threads must be blocked until the writing is complete.
Understanding Mutexes and Semaphores Understanding is a three-edged sword.-- Kosh
//0c The most basic synchronization tool is the mutex. A mutex guarantees mutually exclusive access to a shared resource at any given time. Threads that want to access a resource protected by a mutex must wait until the currently active thread is finished and unlock the mutex. Mutexes are very easy to use, but can drastically slow down threaded code when overused.
Another frequently used tool is the semaphore. Semaphores represent "available resources" that can be acquired by multiple threads at the same time until the resource pool is empty. Additional threads must then wait until the required number of resources are available again. Semaphores are very efficient, as they allow simultaneous access to resources. But improper use often leads to thread starvation, or to deadlock---where two threads block each other indefinitely, each one waiting for a resource the other thread has currently locked.
In Qt, mutexes and semaphores are provided by theQMutex and QSemaphore classes.
Mutually Exclusive ReadersLet's assume that we have one or many reader threads reading from a file, and one or many writer threads writing to the same file. To ensure that the file isn't modified while a thread is reading it, we can use a mutex. For example:
QMutex mutex; void ReaderThread::run() { ... mutex.lock(); read_file(); mutex.unlock(); ... } void WriterThread::run() { ... mutex.lock(); write_file(); mutex.unlock(); ... }
The mutex ensures that only one thread at a time can access the file. This works, but if multiple reader threads run at the same time, the threads will quickly end up spending a large percentage of their total running time waiting for the mutex to become available.
Fast, but Not FairThe next solution uses a semaphore instead of a mutex to give multiple readers simultaneous access to the file.
const int MaxReaders = 32; QSemaphore semaphore(MaxReaders); void ReaderThread::run() { ... semaphore++; read_file(); semaphore--; ... } void WriterThread::run() { ... semaphore += MaxReaders; write_file(); semaphore -= MaxReaders; ... }
With this solution, up to MaxReaders threads can read from the file at the same time. As soon as a writer thread wants to modify the file, it tries to allocateall the semaphore's resources, thus making sure that no other thread can access the file during the write operation.
This approach looks reasonable, but there's a problem with it. The writer thread's chance to get access to all resources decreases rapidly with a growing number of reader threads, up to the point where the writer thread will starve completely. This is becauseQSemaphore's+= operator blocks until the semaphore's resource count is zero, instead of acquiring the resources one by one as they are released by reader threads.
In other words, QSemaphore favors threads that request fewer resources. This is "unfair", but prevents a deadlock, as we will see with the next example.
Fair, but Fairly LimitedIt is tempting to replace the += operator with a loop that calls the ++ operator repeatedly, to solve the problem described above:
void WriterThread::run() { ... for (int i = 0; i < MaxReaders; ++i) semaphore++; write_file(); semaphore -= MaxReaders; ... }
Now the writer thread has a fair chance to allocate all resources. But as soon as there are two writer threads competing for the same semaphore, we could end up with a deadlock, with each thread having some resources, but neither being able to get all the resources it needs.
Share and EnjoyTo remove this limitation, we must introduce a mutex in addition to the semaphore. The mutex is only used by writer threads:
void WriterThread::run() { ... mutex.lock(); for (int i = 0; i < MaxReaders; ++i) semaphore++; mutex.unlock(); write_file(); semaphore -= MaxReaders; ... }
As soon as one writer thread has started to allocate resources from the semaphore, all other writer threads must wait. The reader threads don't use the mutex, so they can work simultaneously as long as the writer thread is inactive. Once the writer thread starts working, it will have a fair chance of acquiring the semaphore.
A Read/Write Mutex ClassWe can encapsulate our solution in a ReadWriteMutex class:
class ReadWriteMutex { public: ReadWriteMutex(int maxReaders = 32) : semaphore(maxReaders) { } void lockRead() { semaphore++; } void unlockRead() { semaphore--; } void lockWrite() { QMutexLocker locker(&mutex); for (int i = 0; i < maxReaders(); ++i) semaphore++; } void unlockWrite() { semaphore -= semaphore.total(); } int maxReaders() const { return semaphore.total(); } private: QSemaphore semaphore; QMutex mutex; };
Here's how we can use it in applications:
ReadWriteMutex mutex; void ReaderThread::run() { ... mutex.lockRead(); read_file(); mutex.unlockRead(); ... } void WriterThread::run() { ... mutex.lockWrite(); write_file(); mutex.unlockWrite(); ... }
For your convenience, the ReadWriteMutex class developed in this article will be made available as a Qt Solution, together with aReadWriteMutexLocker class.
- 关于读锁和写锁最好的一篇文章
- 最好的一篇关于Log4j的使用的文章
- 最好的一篇关于Log4j的使用的文章
- 关于pthread见过的最好的一篇文章
- 打算写一篇关于关键字的文章
- 作文:写一篇关于爱情的文章
- 关于职业规划最好最全面的一篇文章
- 关于JDK,JRE,JVM写的最好的文章。
- 我读过关于面试最好的一篇文章
- 转载一篇关于 接口和抽象类 的文章,写的很好
- 转一篇写得很好的关于iptables原理和流程的文章
- 关于noSQL和WEB数据库发展的一篇文章,写的比较清楚
- 一篇关于session的好文章,写的很详细
- 一篇关于session的好文章,写的很详细
- 转一篇关于反射的文章,写的很好
- 一篇关于session的好文章,写的很详细
- 关于龙芯的一篇文章,写的极好
- 转发一篇写得不错的关于iptables的文章
- 最简单的shell输入参数语句demo--getopts
- Ext.fly 和Ext.get 区别
- Asp.net视图状态的作用
- JSP与SERVLET的关系
- OSI七层模式简单通俗理解
- 关于读锁和写锁最好的一篇文章
- HttpHandler 和HttpModule区别
- 防止头文件重复编译
- requestAnimate 绘制气泡
- 说说我用过的博客系统
- 在github Pages上部署octopress搭建个人博客系统
- 闲时扯谈 - Silverlight母版页的实现
- Andengine 学习笔记 - 图片处理
- Andengine 学习笔记- 加载图片的方法