寻找对我的读者/作家实施的批评

Looking for critique of my reader/writer implementation

本文关键字:作家 我的 寻找      更新时间:2023-10-16

我在C 11中实现了读者/作家问题…我想知道它是什么问题,因为这些事情很难自行预测。

  • 共享数据库:
    • 读者可以访问数据库时
    • 当没有读者或作家时,作家可以访问数据库
    • 一个线程一次操纵状态变量

该示例有3位读者和1位作家,但也使用2个或更多作家....

代码:

class ReadersWriters {
private:
    int AR; // number of active readers
    int WR; // number of waiting readers
    int AW; // number of active writers
    int WW; // number of waiting writers
    mutex lock;
    mutex m;
    condition_variable okToRead;
    condition_variable okToWrite;
    int data_base_variable;
public:
    ReadersWriters() : AR(0), WR(0), AW(0), WW(0), data_base_variable(0) {}
    void read_lock() {
        unique_lock<mutex> l(lock);
        WR++; // no writers exist
        // is it safe to read?
        okToRead.wait(l, [this](){ return WW == 0; });
        okToRead.wait(l, [this](){ return AW == 0; });
        WR--; // no longer waiting
        AR++;  // now we are active
    }
    void read_unlock() {
        unique_lock<mutex> l(lock);
        AR--; // no longer active
        if (AR == 0 && WW > 0) { // no other active readers
            okToWrite.notify_one(); // wake up one writer
        }
    }
    void write_lock() {
        unique_lock<mutex> l(lock);
        WW++; // no active user exist
        // is it safe to write?
        okToWrite.wait(l, [this](){ return AR == 0; });
        okToWrite.wait(l, [this](){ return AW == 0; });
        WW--; // no longer waiting
        AW++; // no we are active
    }
    void write_unlock() {
        unique_lock<mutex> l(lock);
        AW--; // no longer active
        if (WW > 0) { // give priority to writers
            okToWrite.notify_one(); // wake up one writer
        }
        else if (WR > 0) { // otherwize, wake reader
            okToRead.notify_all(); // wake all readers
        }
    }
    void data_base_thread_write(unsigned int thread_id) {
        for (int i = 0; i < 10; i++) {
            write_lock();
            data_base_variable++;
            m.lock();
            cout << "data_base_thread: " << thread_id << "...write: " << data_base_variable << endl;
            m.unlock();
            write_unlock();
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
    void data_base_thread_read(unsigned int thread_id) {
        for (int i = 0; i < 10; i++) {
            read_lock();
            m.lock();
            cout << "data_base_thread: " << thread_id << "...read: " << data_base_variable << endl;
            m.unlock();
            read_unlock();
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
    }
};
int main() {
    // your code goes here
    ReadersWriters rw;
    thread w1(&ReadersWriters::data_base_thread_write, &rw, 0);
    thread r1(&ReadersWriters::data_base_thread_read, &rw, 1);
    thread r2(&ReadersWriters::data_base_thread_read, &rw, 2);
    thread r3(&ReadersWriters::data_base_thread_read, &rw, 3);
    w1.join();
    r1.join();
    r2.join();
    r3.join();
    cout << "nThreads successfully completed..." << endl;
    return 0;
}

反馈:

1。它缺少所有必要的#includes。

2。它假设using namespace std在声明中是不好的样式,因为它用名称空间std污染了您所有的客户

3。锁的发布并不例外:

write_lock();
data_base_variable++;
m.lock();
cout << "data_base_thread: " << thread_id << "...write: " << data_base_variable << endl;
m.unlock();           // leaked if an exception is thrown after m.lock()
write_unlock();       // leaked if an exception is thrown after write_lock()

4coutdata_base_thread_write中的m.lock()包装确实是不必要的,因为write_lock()应该已经提供了独家访问。但是我知道这只是一个演示。

5。我 think 我在读/写逻辑中看到一个错误:

step   1     2     3    4     5    6
WR     0     1     1    1     0    0
AR     0     0     0    0     1    1
WW     0     0     1    1     1    0
AW     1     1     1    0     0    1

在步骤1中,线程1具有写锁。

在步骤2中,线程2尝试获取读取锁,增量WR和第二个okToRead上的块,等待AW == 0

在步骤3中,线程3尝试获取写锁,增量WW和第二个okToWrite上的块,等待AW == 0

在步骤4中,线程1版本,通过将AW降低到0,并发出信号okToWrite

在步骤5中,线程2尽管没有发出信号,但 spuroly 都指出AW == 0,并通过将WR设置为0和AR抓住读取锁定。

在步骤6中,线程3接收信号,指出AW == 0,并通过将WW设置为0和AW和1。

在步骤6中,两个线程2拥有读取锁,线程3拥有写锁(同时)。

6。类ReadersWriters具有两个功能:

  1. 它实现了读/写utex。
  2. 它实现了线程执行的任务。

更好的设计将利用C 11中建立的静音/锁定框架:

用成员创建一个ReaderWriter静音:

// unique ownership
void lock();      // write_lock
void unlock();    // write_unlock
// shared ownership
lock_shared();    // read_lock
unlock_shared();  // read_unlock

前两个名称lockunlock与C 11 Mutex类型所使用的名称有目的地相同。只是这样做可以让您做以下事情:

std::lock_guard<ReaderWriter>  lk1(mut);
// ...
std::unique_lock<ReaderWriter> lk2(mut);
// ...
std::condition_variable_any cv;
cv.wait(lk2);  // wait using the write lock

,如果您添加:

void try_lock();

然后您也可以:

std::lock(lk2, <any other std or non-std locks>);  // lock multiple locks

选择lock_sharedunlock_shared名称是因为当前C 1Y中的std::shared_lock<T>类型(我们希望Y是4)工作草稿。它记录在N3659中。然后您可以说:

std::shared_lock<ReaderWriter> lk3(mut);   // read_lock
std::condition_variable_any cv;
cv.wait(lk3);  // wait using the read lock

即。通过创建一个独立的ReaderWriter MUTEX类型,具有非常仔细的成员函数名称,您可以与STD定义的锁,condition_variable_any和锁定算法获得互操作性。

有关此框架的更深入的理由,请参见N2406。