我们发现在代码中我们有几个位置,其中并发读取受互斥锁保护的数据是相当常见的,而写入很少见.我们的测量结果似乎表明,使用简单的互斥锁严重阻碍了读取数据的代码的性能.所以我们需要的是多读/单写互斥.我知道这可以建立在更简单的原语之上,但在我尝试自己之前,我宁愿要求现有的知识:
从简单的同步原语中构建多读/单写锁的批准方法是什么?
我确实知道如何制作它,但我宁愿通过我(可能是错误的)想出的答案而不偏不倚.(注意:我期望的是如何解释它,可能是伪代码,而不是完整的实现.我当然可以自己编写代码.)
注意事项:
这需要有合理的表现.(我想到的是每次访问需要两次锁定/解锁操作.现在可能不够好,但需要其中许多操作似乎是不合理的.)
通常,读取数量更多,但写入比读取更重要且性能更敏感.读者不能让作家们挨饿.
我们被困在一个相当古老的嵌入式平台(VxWorks 5.5的专有变体)上,有一个相当旧的编译器(GCC 4.1.2)和boost 1.52 - 除了大多数依赖于POSIX的boost部分,因为POSIX没有完全实现在那个平台上.可用的锁定原语基本上是几种信号量(二进制,计数等),我们已经在其上创建了互斥量,条件变量和监视器.
这是IA32,单核.
我有一组数据结构,我需要用读/写锁来保护.我知道boost :: shared_lock,但我想使用std :: mutex,std :: condition_variable和/或std :: atomic进行自定义实现,这样我就能更好地理解它是如何工作的(稍后再调整) .
每个数据结构(可移动但不可复制)将从一个名为Commons的类继承,该类封装了锁定.我希望公共接口看起来像这样:
class Commons {
public:
void read_lock();
bool try_read_lock();
void read_unlock();
void write_lock();
bool try_write_lock();
void write_unlock();
};
Run Code Online (Sandbox Code Playgroud)
...以便某些人可以公开继承:
class DataStructure : public Commons {};
Run Code Online (Sandbox Code Playgroud)
我正在编写科学代码,通常可以避免数据争用; 这种锁定主要是为了防止我以后可能犯的错误.因此,我的优先级是低读取开销,所以我不会妨碍正确运行的程序太多.每个线程可能都在自己的CPU核心上运行.
你能告诉我(伪代码是好的)读者/作家锁吗?我现在所拥有的应该是防止作家饥饿的变种.到目前为止,我的主要问题是read_lock在检查读取是否可以安全地实际递增读取器计数之间的差距,之后write_lock知道等待.
void Commons::write_lock() {
write_mutex.lock();
reading_mode.store(false);
while(readers.load() > 0) {}
}
void Commons::try_read_lock() {
if(reading_mode.load()) {
//if another thread calls write_lock here, bad things can happen
++readers;
return true;
} else return false;
}
Run Code Online (Sandbox Code Playgroud)
我对多线程有点新意,我真的很想理解它.在此先感谢您的帮助!
Mutex
一次只能有一个读者或作者,RwLock
一次可以有一个作家或多个读者.当你这样说的时候,RwLock
似乎总是更好(更少限制)Mutex
,为什么我会使用它呢?
来自ReentrantLock javadoc:
公平模式
当构建为公平时,线程使用近似 到达顺序策略争用进入.当释放当前保持的锁时,将为最长等待的单个写入器线程分配写锁定,或者如果有一组读取器线程等待的时间长于所有等待的写入器线程,则将为该组分配读锁定.尝试获取公平读锁定(非重复)的线程将阻止是否保持写锁定,或者存在等待写入器线程.在最旧的当前等待的写入器线程获取并释放写锁定之前,线程将不会获取读锁定.当然,如果等待的写入者放弃其等待,将一个或多个读取器线程作为队列中最长的服务器并且写锁定空闲,那么将为这些读取器分配读锁定.
尝试获取公平写锁定(非重复)的线程将阻塞,除非读锁定和写锁定都是空闲的(这意味着没有等待线程).(请注意,非阻塞ReentrantReadWriteLock.ReadLock.tryLock()和ReentrantReadWriteLock.WriteLock.tryLock()方法不遵循此公平设置,并且如果可能,将获取锁定,无论等待线程如何.)
也许这是我的英语问题,但我看到这个解释的矛盾:
从第一个paragrapgh我不明白大约到达订单政策的意义
请澄清这一矛盾.
当同步对共享资源的访问时,除了它具有比我可能需要的更多功能的哲学原因之外,是否还有理由不使用读/写锁而不使用普通互斥锁(这基本上只是一个写锁) ?
换句话说,如果我只是默认将读/写锁作为我首选的同步结构,我是否会搬起石头砸自己的脚?
在我看来,始终选择读/写锁并相应地使用读锁与写锁的一个很好的理由是我可以实现一些同步,然后永远不必再考虑它,同时获得更好性能的可能好处如果有一天我将代码放入一个竞争更激烈的环境中,那么将来的可扩展性就会增加。因此,假设它有潜在的好处而没有实际成本,那么一直使用它是有意义的。那有意义吗?
这是在一个资源并不真正受限的系统上,这可能更多是一个性能问题。另外,我已经笼统地表达了这个问题,但如果重要的话,我会特别考虑 QtQReadWriteLock
和(C++)。QMutex
language-agnostic performance multithreading mutex readwritelock
考虑一个原始类型变量,其中包含许多线程读取和几个线程写入,以下代码是否可以正常工作?
如果它会,它提供比1)更好的性能.声明所有方法的同步; 2).使用显式ReadWriteLock?
这是一种常见的模式吗?如果没有,在这种情况下通常使用什么模式?
这对我来说当前工作正常,但我觉得使用volatile和synchronized有点多余.
private volatile int value = 1;
public void func1()
{
if (value == 1) {
// do something
}
}
public void func2()
{
if (value == 2) {
// do something
}
}
public void func3()
{
if (value == 3) {
// do something
}
}
public synchronized void increase()
{
if (value < 10) value++;
}
public synchronized void decrease()
{
if (value > 0) value--;
}
Run Code Online (Sandbox Code Playgroud) 我正在寻找高效的系统,以便分层组织一系列读/写锁,以管理对分层组织资源的访问.如果一个子树被锁定以进行写入,那么在它被释放之前,不应该在整个子树中获得其他锁定; 类似地,子树中的写锁定应该防止在父节点中锁定.
以下是我正在考虑的想法:
使用Apache Commons Transaction.不幸的是,该项目自2008年3月以来一直没有更新,并且已经非正式终止.一些API文档似乎表明即将推出的版本(1.3或2.0)将包含某种层次锁定,但源代码无处可寻,似乎我们无法再访问其SVN存储库.
使用一系列ReentrantReadWriteLock
s,我将按层次结构组织.我不是并发专家,我有点害怕自己这样做.初步想法似乎表明,即使在我尝试锁定一个子树之前,我必须在管理ReentrantReadWriteLock
s本身的整个结构上使用外锁- 这样即使释放一个锁,我也必须使用外锁...
使用来自java.util.concurrent
和java.util.concurrent.atomic
实现我的分层锁的类比我用一系列ReentrantReadWriteLock
s 更有效.
我已经准备好走最后一条路,但我很惊讶没有找到任何可以更好地解决这个问题的现有图书馆.所以:
我正在研究Workflow like system.我有一个任务表和状态字段.状态值可以是新的,准备好的,处理的,错误的,中止的,完成的.
我有大约7个过程,它们将根据不同的情况触发,以改变任务状态的值.大多数时候,每个进程都可以在自己的数据集上工作,每次只处理多达5000条记录.但如果数据达到约200万条记录,我仍然会看到一些僵局.我检查SQL Profiler,看起来像一些页面资源相关.我不擅长sql server性能调优,也不太了解它.
由于非活动任务将每天存档,我想重新设计该表以支持大约1000万条记录.
几个选择可能是:
这种情况有什么好的做法吗?
谢谢!
以下是典型的读写器模式(大量读取和少量写入)
private ReadWriteLock lock = new ReentrantReadWriteLock();
private int value;
public void writeValue(int newValue){
lock.writeLock().lock();
try{
this.value = newValue;
}
finally{
lock.writeLock().unlock();
}
}
public int readValue(){
lock.readLock().lock();
try{
return value;
}
finally{
lock.writeLock().unlock();
}
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否有可能优先考虑作家和读者?例如,通常编写者可能会等待很长时间(可能永远),如果其他线程持有读取锁定,那么是否可以让编写器具有更高的优先级,因此每当编写器出现时,它都可以被认为是正如高优先级(跳过线)类似的东西.
java multithreading reentrantreadwritelock readwritelock reentrantlock
我有一些数据结构,我想在其中独占锁定写入访问,但启用并行读取访问。
我进行了一些搜索,找到了类ReadWriteLock
和ReentrantReadWriteLock
- 它们都提供读锁和写锁。
我不明白它们之间有什么区别。有人可以解释一下吗?
readwritelock ×10
java ×5
locking ×3
c++ ×2
concurrency ×2
mutex ×2
performance ×2
c++11 ×1
hierarchical ×1
reentrancy ×1
rust ×1
sql-server ×1
synchronized ×1
volatile ×1