提升shared_lock.阅读首选?

ano*_*aut 15 c++ boost

我正在查看用于读取器/写入器锁的boost库(版本1.45).当我对它进行测试时,似乎shared_ptr更喜欢我的读取器线程,即当我的编写器试图锁定它的操作时,它并没有阻止任何后续读取发生.

是否有可能在提升中改变这种行为?

using namespace std;
using namespace boost;

mutex outLock;
shared_mutex workerAccess;
bool shouldIWork = true;

class WorkerKiller
{
public:   

    void operator()()  
    {
        upgrade_lock<shared_mutex> lock(workerAccess); 
        upgrade_to_unique_lock<shared_mutex> uniqueLock(lock);

        cout << "Grabbed exclusive lock, killing system" << endl;
        sleep(2);
        shouldIWork = false;
        cout << "KILLING ALL WORK" << endl;  
    }  

private:  
};

class Worker
{  
public:   

    Worker()
    {  
    }  

    void operator()()  
    {
        shared_lock<shared_mutex> lock(workerAccess); 

        if (!shouldIWork) {
            outLock.lock();
            cout << "Workers are on strike.  This worker refuses to work" << endl;
            outLock.unlock();
        } else {
            sleep(1);

            outLock.lock(); 
            cout << "Worked finished her work" << endl;
            outLock.unlock(); 
        }
    }  
};  

int main(int argc, char* argv[])  
{  
    Worker w1;
    Worker w2;
    Worker w3;
    Worker w4;
    WorkerKiller wk;

    boost::thread workerThread1(w1);
    boost::thread workerThread2(w2);

    boost::thread workerKillerThread(wk);

    boost::thread workerThread3(w3);
    boost::thread workerThread4(w4);

    workerThread1.join();
    workerThread2.join();
    workerKillerThread.join();
    workerThread3.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

以下是每次输出:

工作完成了她的工作
工作完成了她的工作
工作完成了她的工作
工作完成了她的工作
抓住了独家锁定,杀死系统杀死
所有工作

我的要求

如果作者试图获取一个独占锁,我希望所有以前的读操作都能完成.然后所有后续的读操作都要阻止.

How*_*ant 28

我对这个问题有点迟,但我相信我有一些相关的信息.

shared_mutex提升库所依据的C++委员会的提议,故意没有指定API给读者和作者优先权.这是因为亚历山大·特列霍夫(Alexander Terekhov)在十年前提出了一种完全公平的算法.它允许操作系统决定获取互斥锁的下一个线程是读者还是编写者,操作系统完全不知道下一个线程是读者还是编写者.

由于该算法,指定读者或作者是否优选的需要消失.据我所知,现在使用这种公平算法实现了升压库(升级1.52).

Terekhov算法包括使读/写互斥由两个门组成:gate1和gate2.一次只能有一个线程通过每个门.可以使用互斥锁和两个条件变量来实现门.

读者和作者都试图通过gate1.为了通过gate1,写入线程当前不在gate1内部.如果有,则线程试图通过gate1块.

读取器线程通过gate1后,它已读取互斥锁的所有权.

当编写器线程通过gate1时,它必须在获得互斥锁的写入所有权之前通过gate2.在gate1内部的读取器数量降至零之前,它无法通过gate2.

这是一个公平的算法,因为当gate1内部只有0个或更多的读取器时,操作系统将决定下一个进入gate1的线程是读者还是写入者.只有在通过gate1之后,编写器才会被"优先",因此下一步就是获得互斥锁的所有权.

我使用你的例子编译了最终成为shared_timed_mutexC++ 14的一个示例实现(对你的例子稍作修改).下面的代码调用它shared_mutex,这是它提出时的名称.

我得到以下输出(都具有相同的可执行文件):

有时:

Worked finished her work
Worked finished her work
Grabbed exclusive lock, killing system
KILLING ALL WORK
Workers are on strike.  This worker refuses to work
Workers are on strike.  This worker refuses to work
Run Code Online (Sandbox Code Playgroud)

而有时:

Worked finished her work
Grabbed exclusive lock, killing system
KILLING ALL WORK
Workers are on strike.  This worker refuses to work
Workers are on strike.  This worker refuses to work
Workers are on strike.  This worker refuses to work
Run Code Online (Sandbox Code Playgroud)

而有时:

Worked finished her work
Worked finished her work
Worked finished her work
Worked finished her work
Grabbed exclusive lock, killing system
KILLING ALL WORK
Run Code Online (Sandbox Code Playgroud)

我认为理论上也可以获得其他输出,尽管我没有通过实验确认.

为了完全公开,这里是我执行的确切代码:

#include "../mutexes/shared_mutex"
#include <thread>
#include <chrono>
#include <iostream>

using namespace std;
using namespace ting;

mutex outLock;
shared_mutex workerAccess;
bool shouldIWork = true;

class WorkerKiller
{
public:   

    void operator()()  
    {
        unique_lock<shared_mutex> lock(workerAccess); 

        cout << "Grabbed exclusive lock, killing system" << endl;
        this_thread::sleep_for(chrono::seconds(2));
        shouldIWork = false;
        cout << "KILLING ALL WORK" << endl;  
    }  

private:  
};

class Worker
{  
public:   

    Worker()
    {  
    }  

    void operator()()  
    {
        shared_lock<shared_mutex> lock(workerAccess); 

        if (!shouldIWork) {
            lock_guard<mutex> _(outLock);
            cout << "Workers are on strike.  This worker refuses to work" << endl;
        } else {
            this_thread::sleep_for(chrono::seconds(1));

            lock_guard<mutex> _(outLock);
            cout << "Worked finished her work" << endl;
        }
    }  
};  

int main()  
{  
    Worker w1;
    Worker w2;
    Worker w3;
    Worker w4;
    WorkerKiller wk;

    thread workerThread1(w1);
    thread workerThread2(w2);

    thread workerKillerThread(wk);

    thread workerThread3(w3);
    thread workerThread4(w4);

    workerThread1.join();
    workerThread2.join();
    workerKillerThread.join();
    workerThread3.join();
    workerThread4.join();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)