Я видел файл заголовка, как показано ниже:
#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
}
...
Итак, как работает этот макрос блокировки? И почему?
Мы можем сделать небольшое макрообъем на бумаге здесь:
Ваш макрос =
#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
).
Таким образом, препроцессор будет расширять макрос на месте (по существу, вставляя его в код). Итак, ваш пример:
...
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.
Lock
есть конструктор, который используетMutex&
.