如果我有一个线程写入和多个读取,我如何只在写入时锁定而不是读取?

Posted

技术标签:

【中文标题】如果我有一个线程写入和多个读取,我如何只在写入时锁定而不是读取?【英文标题】:If I have one thread writing and many reading, how can I only lock when writing, but not reading? 【发布时间】:2015-11-26 19:30:17 【问题描述】:

所以我有这个结构到我正在写的缓存:

struct scache 
        char* rp;
        int ce;
        char* code;
        struct headers* headers;
        struct body* body;
;

struct dcache 
        unsigned char md5[16];
        struct scache scache;
;

struct cache 
        struct scache** scaches;
        size_t scache_size;
        struct dcache** dcaches;
        size_t dcache_size;
;

struct scache* getSCache(struct cache* cache, char* rp, int ce);

struct dcache* getDCache(struct cache* cache, char* rp, int ce, unsigned char* md5);

int addSCache(struct cache* cache, struct scache* scache);

int addDCache(struct cache* cache, struct dcache* dcache);

我想使用互斥锁,这样我在写作时就不能允许任何读取,但不会让读取阻塞其他读取。所以读线程不会互相阻塞,但是如果一个加一个,就会阻塞其他的读写。

我研究了互斥体,但我不知道如何实现这一权利。我想我可以锁定写入,但是如果读取看到的大小比实际大小更大或更小,然后读取不足或过度读取,都会导致双重缓存或内存损坏问题。

【问题讨论】:

您可以使用_Atomicstdatomic.h(C11 起)。比互斥锁等更轻量级,但实现起来可能更复杂,具体取决于实际数据类型。 请注意,读取也必须是原子的。这很可能需要针对中间写入进行锁定。更不用说编译器和/或硬件对指令/内存访问重新排序等其他问题了。 @Olaf 原子性和读写锁定是两个完全不同的概念。如果可用,正确实现读写锁将使用原子操作。 @Let_Me_Be:我没有说它们是相同的,但它们可能是相关的,虽然现代 CPU 为基本类型提供原子读/写,但它们需要更多的复合数据类型。并且还有锁定的替代方法,例如具有硬件支持的更改检测的独占访问,例如 ARMs LDREX/STREX 指令。但是,有时锁定比重试更有效。一切都取决于实际使用情况,例如访问频率。请注意,实际上有两个级别的原子访问。硬件/低级和更复杂的结构。 【参考方案1】:

你想要的是一个读写锁。根据偏向的方式,有不同的实现方式。

两个边界极端是:

写入可立即访问 只有在有 0 个读取等待时写入才能访问

大多数实现都偏向写入或读取。

有关标准 POSIX 实现,请参阅:pthread_rwlock_thttp://pubs.opengroup.org/onlinepubs/007908799/xsh/pthread_rwlock_init.html

【讨论】:

以上是关于如果我有一个线程写入和多个读取,我如何只在写入时锁定而不是读取?的主要内容,如果未能解决你的问题,请参考以下文章

允许多个线程一次读取给定条件变量,但只有一个线程写入

如何在 C++ 中的 unordered_map 的并发读取和锁定单线程写入之间交替

如果仅写入值,我是不是需要原子?

防止共享哈希表中的数据竞争

是否存在多个读取或写入线程的无锁队列?

是否可以同时读取和写入 java.net.Socket?