реализация блокировки чтения / записи с использованием только мьютекса? - PullRequest
4 голосов
/ 26 декабря 2011

Я пытался реализовать блокировку чтения / записи, используя только мьютекс (только для обучения). Когда я подумал, что покрыл все угловые случаи (поскольку программа работала с различными комбинациями), я понял, что проигнорировал тот факт (как он работал в Ubuntu), что мьютекс должен быть освобожден владельцем потока. Ниже моя реализация,

class rw_lock_t{

    int NoOfReaders;
    int NoOfWriters, NoOfWritersWaiting;
    pthread_mutex_t class_mutex;
    pthread_cond_t class_cond;
    pthread_mutex_t data_mutex;

public:

    rw_lock_t()
    : NoOfReaders(0),
      NoOfWriters(0), NoOfWritersWaiting(0)
    {
            pthread_mutex_init(&class_mutex, NULL);
            pthread_mutex_init(&data_mutex, NULL);
            pthread_cond_init(&class_cond, NULL);
    }
    void r_lock()
    {
            pthread_mutex_lock(&class_mutex);
            //while(NoOfWriters!=0 || NoOfWritersWaiting!=0) //Writer Preference
            while(NoOfWriters!=0)
            {
                    pthread_cond_wait(&class_cond, &class_mutex);
            }
            if(NoOfReaders==0)
            {
                    pthread_mutex_unlock(&class_mutex);
                    pthread_mutex_lock(&data_mutex);
                    pthread_mutex_lock(&class_mutex);
                    NoOfReaders++;
                    pthread_mutex_unlock(&class_mutex);
            }
            else if(NoOfReaders>0) //Already Locked
            {
                    NoOfReaders++;
                    pthread_mutex_unlock(&class_mutex);
            }
    }
    void w_lock()
    {
            pthread_mutex_lock(&class_mutex);
            NoOfWritersWaiting++;
            while(NoOfReaders!=0 && NoOfWriters!=0)
            {
                    pthread_cond_wait(&class_cond, &class_mutex);
            }
            pthread_mutex_unlock(&class_mutex);

            pthread_mutex_lock(&data_mutex);
            pthread_mutex_lock(&class_mutex);
            NoOfWritersWaiting--; NoOfWriters++;
            pthread_mutex_unlock(&class_mutex);
    }
    void r_unlock()
    {
            pthread_mutex_lock(&class_mutex);
            NoOfReaders--;
            if(NoOfReaders==0)
                    pthread_mutex_unlock(&data_mutex);
            pthread_mutex_unlock(&class_mutex);
            pthread_cond_signal(&class_cond);
    }
    void w_unlock()
    {
            pthread_mutex_lock(&class_mutex);
            NoOfWriters--;
            if(NoOfWriters==0)
                    pthread_mutex_unlock(&data_mutex);
            pthread_mutex_unlock(&class_mutex);
            pthread_cond_signal(&class_cond);
    }
};

Мой вопрос сейчас заключается в том, каков наилучший способ (минимальное изменение) исправить. Семафор определенно не используется, но я подумал о решениях ниже

Решение # 1

1) У меня будет специальный поток, просто для блокировки / разблокировки мьютекса для чтения.

2) Этот поток будет ожидать переменную условия для получения сигнала от r_lock или r_unlock.

3) r_lock и r_unlock вместо "pthread_mutex_lock / unlock (& ​​data_mutex);" будут сигнализировать о блокировке выделенного потока.

4) Мне нужно запомнить много фактов для этой реализации,

  • Сигнализация и фактическая блокировка - это два разных события, поэтому может потребоваться синхронизация.

  • Потребуется мьютекс + condVariable + поток и дополнительная синхронизация.

Обновление: решение № 2

1) Поток, выполнивший фактическую блокировку, сохранит свою информацию глобально.

2) всякий раз, когда поток разблокируется, проверяется равенство проверки с глобальным значением.

3) Если совпадения будут ждать условия «NoOfReaders == 0» и разблокировать его.

Итак, есть ли лучший способ исправления программы.

Ответы [ 2 ]

9 голосов
/ 29 января 2012

Вам не нужен отдельный мьютекс «для данных»; вся конструкция будет служить блокировкой данных, если ее внутренняя логика верна. Вместо этого вы можете использовать две отдельные переменные условия для читателей и писателей, чтобы вы могли транслировать всех ожидающих читателей, не влияя на ожидающих писателей. Код ниже; Вы также можете видеть, что так проще. Кроме того, я добавил деструктор и исправил ошибку в w_lock: условие ожидания должно быть (NoOfReaders!=0 || NoOfWriters!=0), а не &&.

class rw_lock_t {

    int NoOfReaders;
    int NoOfWriters, NoOfWritersWaiting;
    pthread_mutex_t class_mutex;
    pthread_cond_t  reader_gate;
    pthread_cond_t  writer_gate;

public:

    rw_lock_t()
    : NoOfReaders(0), NoOfWriters(0), NoOfWritersWating(0),
      class_mutex(PTHREAD_MUTEX_INITIALIZER),
      reader_gate(PTHREAD_COND_INITIALIZER),
      writer_gate(PTHREAD_COND_INITIALIZER)
    {}
    ~rw_lock_t()
    {
        pthread_mutex_destroy(&class_mutex);
        pthread_cond_destroy(&reader_gate);
        pthread_cond_destroy(&writer_gate);
    }
    void r_lock()
    {
        pthread_mutex_lock(&class_mutex);
        //while(NoOfWriters>0 || NoOfWritersWaiting>0) //Writer Preference
        while(NoOfWriters>0)
        {
            pthread_cond_wait(&reader_gate, &class_mutex);
        }
        NoOfReaders++;        
        pthread_mutex_unlock(&class_mutex);
    }
    void w_lock()
    {
        pthread_mutex_lock(&class_mutex);
        NoOfWritersWaiting++;
        while(NoOfReaders>0 || NoOfWriters>0)
        {
            pthread_cond_wait(&writer_gate, &class_mutex);
        }
        NoOfWritersWaiting--; NoOfWriters++;
        pthread_mutex_unlock(&class_mutex);
    }
    void r_unlock()
    {
        pthread_mutex_lock(&class_mutex);
        NoOfReaders--;
        if(NoOfReaders==0 && NoOfWritersWaiting>0)
            pthread_cond_signal(&writer_gate);
        pthread_mutex_unlock(&class_mutex);
    }
    void w_unlock()
    {
        pthread_mutex_lock(&class_mutex);
        NoOfWriters--;
        if(NoOfWritersWaiting>0)
            pthread_cond_signal(&writer_gate);
        //else //Writer Preference - don't signal readers unless no writers
        pthread_cond_broadcast(&reader_gate);
        pthread_mutex_unlock(&class_mutex);
    }
};
0 голосов
/ 16 сентября 2014
class ReadWriteLock {
    mutex writeLock;
    mutex readLock;
    int readCount;
public:
    ReadWriteLock() {
        readCount = 0;
    }
    void LockWrite() {
        writeLock.lock();
    }
    void UnlockWrite() {
        writeLock.unlock();
    }
    void LockRead() {
        lock_guard<mutex> lock(readLock);
        ++readCount;
        if (1 == readCount) {
            LockWrite();
        }
    }
    void UnlockRead() {
        lock_guard<mutex> lock(readLock);
        --readCount;
        if (0 == readCount) {
            UnlockWrite();
        }
    }
};

Как указал Алексей, если последний поток чтения UnlockWrite не является первым потоком чтения LockWrite, поведение не определено.См. Std :: mutex :: unlock http://www.cplusplus.com/reference/mutex/mutex/unlock/ Windows ReleaseMutex: http://msdn.microsoft.com/en-us/library/windows/desktop/ms685066(v=vs.85).aspx

...