问题描述
我不确定我的术语是否正确,但这里是 - 我有这个函数被多个线程用来写入数据(在注释中使用伪代码来说明我想要的)
I'm not sure I got the terminology right but here goes - I have this function that is used by multiple threads to write data (using pseudo code in comments to illustrate what I want)
//these are initiated in the constructor
int* data;
std::atomic<size_t> size;
void write(int value) {
//wait here while "read_lock"
//set "write_lock" to "write_lock" + 1
auto slot = size.fetch_add(1, std::memory_order_acquire);
data[slot] = value;
//set "write_lock" to "write_lock" - 1
}
写入的顺序并不重要,我需要的只是让每次写入都转到一个唯一的槽
the order of the writes is not important, all I need here is for each write to go to a unique slot
虽然每隔一段时间,我需要一个线程来使用这个函数读取数据
Every once in a while though, I need one thread to read the data using this function
int* read() {
//set "read_lock" to true
//wait here while "write_lock"
int* ret = data;
data = new int[capacity];
size = 0;
//set "read_lock" to false
return ret;
}
所以它基本上交换了缓冲区并返回旧的(我删除了容量逻辑以缩短代码段)
so it basically swaps out the buffer and returns the old one (I've removed capacity logic to make the snippets shorter)
理论上这应该会导致 2 个操作场景:
In theory this should lead to 2 operating scenarios:
1 - 只是一堆写入容器的线程
1 - just a bunch of threads writing into the container
2 - 当某个线程执行读取函数时,所有新的写入器都必须等待,读取器将等待所有现有写入完成,然后执行读取逻辑,场景 1 可以继续.
2 - when some thread executes the read function, all new writers will have to wait, the reader will wait until all existing writes are finished, it will then do the read logic and scenario 1 can continue.
问题部分是我不知道锁使用什么样的屏障-
The question part is that I don't know what kind of a barrier to use for the locks -
自旋锁会很浪费,因为有很多这样的容器,而且它们都需要 CPU 周期
A spinlock would be wasteful since there are many containers like this and they all need cpu cycles
我不知道如何应用 std::mutex,因为我只希望在触发读取函数时写入函数位于临界区.将整个写入函数包装在互斥体中会导致操作场景 1 的不必要的减速.
I don't know how to apply std::mutex since I only want the write function to be in a critical section if the read function is triggered. Wrapping the whole write function in a mutex would cause unnecessary slowdown for operating scenario 1.
那么这里的最佳解决方案是什么?
So what would be the optimal solution here?
推荐答案
如果您有 C++14
能力,那么您可以使用 std::shared_timed_mutex 将读者和作者分开.在这种情况下,您似乎需要给您的编写线程共享访问(同时允许其他编写线程)和您的读者线程唯一访问(将所有其他线程踢出).
If you have C++14
capability then you can use a std::shared_timed_mutex to separate out readers and writers. In this scenario it seems you need to give your writer threads shared access (allowing other writer threads at the same time) and your reader threads unique access (kicking all other threads out).
因此,您可能需要这样的东西:
So something like this may be what you need:
class MyClass
{
public:
using mutex_type = std::shared_timed_mutex;
using shared_lock = std::shared_lock<mutex_type>;
using unique_lock = std::unique_lock<mutex_type>;
private:
mutable mutex_type mtx;
public:
// All updater threads can operate at the same time
auto lock_for_updates() const
{
return shared_lock(mtx);
}
// Reader threads need to kick all the updater threads out
auto lock_for_reading() const
{
return unique_lock(mtx);
}
};
// many threads can call this
void do_writing_work(std::shared_ptr<MyClass> sptr)
{
auto lock = sptr->lock_for_updates();
// update the data here
}
// access the data from one thread only
void do_reading_work(std::shared_ptr<MyClass> sptr)
{
auto lock = sptr->lock_for_reading();
// read the data here
}
shared_lock 允许其他线程获得 shared_lock 但防止 unique_lock 获得同时访问.当读者线程试图获得 unique_lock 所有 shared_locks 将在 unique_lock 获得独占控制权.
The shared_locks allow other threads to gain a shared_lock at the same time but prevent a unique_lock gaining simultaneous access. When a reader thread tries to gain a unique_lock all shared_locks will be vacated before the unique_lock gets exclusive control.
这篇关于使用互斥锁阻止来自临界区外部的执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!