Как работает этот блок блокировки?

0

Я видел файл заголовка, как показано ниже:

#include <pthread.h>

#define lock(x) if(Lock _lock_=x){}else

class Mutex{
    public:
        Mutex(){
            pthread_mutex_init(&mutex_, 0);
        };

        ~Mutex(){
            pthread_mutex_destroy(&mutex_);
        };

        friend class Lock;

    private:
        pthread_mutex_t mutex_;

        void Lock(){
            pthread_mutex_lock(&mutex_);
        };

        void Unlock(){
            pthread_mutex_unlock(&mutex_);
        };
};

class Lock{
    public:
        Lock(Mutex& mutex):mutex_(mutex){mutex_.Lock();};
        ~Lock(){mutex_.Unlock();};

        operator bool() const {
            return false;
        }

    private:
        Mutex& mutex_;
};

Он определяет макрос lock(x). Ниже приведен пример использования этого макроса:

...
Mutex mtx;
lock(mtx) {
  // critical section
}
...

Итак, как работает этот макрос блокировки? И почему?

Теги:
multithreading
locking

2 ответа

1
Лучший ответ

Мы можем сделать небольшое макрообъем на бумаге здесь:

Ваш макрос =

#define lock(x) if(Lock _lock_=x){}else

И использование этого:

Mutex mtx;
lock(mtx) {
  // critical section
}

Становится после макроподстановки:

Mutex mtx;
if(Lock _lock_=mtx)
{
  // BLOCK 1
}
else
{
  // BLOCK 2
  // critical section
}

Таким образом, _lock_ копией из mtx, который пытается заблокировать мьютекс, вызывая pthread_mutex_lock, который возвращает 0 если он успешный, и блокирует, если мьютекс уже заблокирован.

Блок if вызывает функцию Lock::operator bool(), которая всегда возвращает false:

operator bool() const {return false; } }

Так как это всегда возвращает false, блок я markeed BLOCK 1 никогда не берется, и вместо этого вызывается ваш критический код раздела (BLOCK 2).

  • 0
    Почему он может использовать copy-assign из типа Mutex для типа Lock?
  • 0
    @injoy: Потому что у Lock есть конструктор, который использует Mutex& .
Показать ещё 3 комментария
2

Таким образом, препроцессор будет расширять макрос на месте (по существу, вставляя его в код). Итак, ваш пример:

...
Mutex mtx;
if(Lock _lock_=mtx){}else {
  // critical section
}
...

Или, с некоторым лучшим форматированием,

...
Mutex mtx;
if(Lock _lock_=mtx)
{
}
else
{
  // critical section
}
...

Он блокирует Mutex через конструктор класса Lock, и выражение в выражении if() всегда вычисляется как false из-за реализации operator bool() const Lock operator bool() const, поэтому выполняется код в части else { }.

Я думаю, я также упомянул, что я бы сказал, что это... более сложный, чем необходимый способ сделать это. Было бы "так же легко" (и, вероятно, более понятным) просто объявить новый Lock в начале вашей области действия и полностью отказаться от макроса. Так используется, например, Qt QMutexLocker.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню