提升shared_lock。阅读首选?

时间:2012-08-22 22:43:35

标签: c++ boost

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

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

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;
}

以下是每次输出:

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

我的要求

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

2 个答案:

答案 0 :(得分:27)

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

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

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

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

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

一旦读者线程通过gate1,它就会读取互斥锁的所有权。

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

这是一个公平的算法,因为当gate1中只有0个或更多读者时,操作系统是否要进入gate1的下一个线程是读者还是写入者。只有在编写器通过gate1之后,编写器才会“优先”,从而获得互斥锁的所有权。

我使用你的例子编译了一个最终在C ++ 14中变成shared_timed_mutex的示例实现(对你的例子稍作修改)。下面的代码将其称为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

有时候:

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

有时候:

Worked finished her work
Worked finished her work
Worked finished her work
Worked finished her work
Grabbed exclusive lock, killing system
KILLING ALL WORK

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

为了充分披露,以下是我执行的确切代码:

#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;
}

答案 1 :(得分:1)

谷歌搜索“提升共享锁定饥饿”出现了这个链接:

看起来“升级”可能是关键。另见: