使用互斥锁阻止从关键部分外部执行

use*_*993 7 c++ multithreading

我不确定我的术语是否正确但是这里有 - 我有这个函数,多个线程用来写数据(在注释中使用伪代码来说明我想要的)

//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
}
Run Code Online (Sandbox Code Playgroud)

写入的顺序并不重要,我需要的是每次写入都要转到一个唯一的插槽

虽然每隔一段时间,我需要一个线程来使用此函数读取数据

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;
}
Run Code Online (Sandbox Code Playgroud)

所以它基本上交换了缓冲区并返回旧缓冲区(我删除了容量逻辑以使代码片段更短)

从理论上讲,这应该导致2种操作场景:

1 - 只是一堆写入容器的线程

2 - 当某个线程执行读取功能时,所有新写入器都必须等待,读取器将等待所有现有写入完成,然后它将执行读取逻辑并且方案1可以继续.

问题部分是我不知道锁用什么样的障碍 -

螺旋锁是浪费的,因为有很多像这样的容器,它们都需要cpu循环

我不知道如何应用std :: mutex,因为我只想让write函数在触发读取函数时处于临界区.将整个写入函数包含在互斥锁中会导致操作方案1不必要地减速.

那么这里的最佳解决方案是什么?

Gal*_*lik 2

如果您有C++14能力,那么您可以使用std::shared_timed_mutex来分离读取器和写入器。在这种情况下,您似乎需要为编写器线程提供共享访问权限(同时允许其他编写器线程),并为读取器线程提供唯一访问权限(将所有其他线程踢出)。

所以你可能需要这样的东西:

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
}
Run Code Online (Sandbox Code Playgroud)

Shared_lock允许其他线程同时获得shared_lock ,但阻止unique_lock获得同时访问。当读取器线程尝试获得 unique_lock 时,unique_lock获得独占控制之前,所有共享锁都将被腾空。