Проблема с доступом к переменной из разных потоков с помощью QAtomicInt
Всем Доброго здравия!
есть класс Device у него есть счетчик m_time, значение которого может асинхронно относительно основного потока изменяться по таймеру или пользователем. Какие мне нужно применить механизмы синхронизации, что избежать одновременного обращения к переменной m_time? вот моя наивная реализация кода:
#include <QtWidgets>
class Device : public QObject {
Q_OBJECT
private:
uint m_time;
QTimer* m_ptimer;
bool m_isChanging;
bool m_isClocking;
public:
Device(QObject* pobj = 0) : QObject(pobj)
, m_time(10)
, m_isChanging(false)
, m_isClocking(false)
{
m_ptimer = new QTimer(this);
connect(m_ptimer, SIGNAL(timeout()), SLOT(setNextValue()));
m_ptimer->start(1000);
}
signals:
void valueChanged(int);
void change ( );
public slots:
void slotChangeValue(int value)
{
if (!m_isClocking) // если не инкремент-тится то изменяем значение
{
m_isChanging = true;
m_time = value;
m_isChanging = false;
}
else
{
// счетчик занят, пробуйте изменить значение позже
}
}
private slots:
void setNextValue()
{
if (!m_isChanging) // если не значение не занято редактированием, то инкремент-им
{
m_isClocking = true;
++m_time;
m_isClocking = false;
}
else
{
// пропуск одно "тика" не критичен
}
}
};
QRandomGenerator *rg = QRandomGenerator::global();
// ----------------------------------------------------------------------
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Device worker;
// имитируем рамдомное редактирование счетчика пользователем
while (true)
{
int change = rg->bounded(1, 100);
if (change % 2 == 0)
{
worker.slotChangeValue(change);
}
}
int nResult = app.exec();
return nResult;
}
Хотелось бы обойтись без блокирующей синхронизации типа QMutexLocker, например сделать переменную атомарной QAtomicInt m_time; но нужны ли тогда флаги m_isChanging, m_isClocking?
Ответы (1 шт):
Автор решения: kitworker
→ Ссылка
Учитывая замечания, так вроде работает:
#include <QtWidgets>
#include <QDebug>
// ======================================================================
QRandomGenerator *rg = QRandomGenerator::global();
class UserTest : public QThread {
Q_OBJECT
public:
void run()
{
while (!isInterruptionRequested())
{
int change = rg->bounded(1, 100);
emit setValue(change);
msleep(change);
}
}
signals:
void setValue(int);
};
class Device : public QObject {
Q_OBJECT
private:
QAtomicInt m_time;
QTimer* m_ptimer;
public:
Device(QObject* pobj = 0) : QObject(pobj)
, m_time(10)
{
m_ptimer = new QTimer(this);
connect(m_ptimer, SIGNAL(timeout()), SLOT(setNextValue()));
m_ptimer->start(100);
}
signals:
void valueChanged(int);
void sendValue(int);
public slots:
void slotChangeValue(int value)
{
Q_ASSERT(m_time < 200);
m_time.store(value);
qDebug() << m_time;
//else счетчик занят, пробуйте изменить значение позже
}
private slots:
void setNextValue()
{
Q_ASSERT(m_time < 200);
m_time.fetchAndAddOrdered(1);
qDebug() << m_time;
sendValue(m_time);
// пропуск одно "тика" не критичен
}
};
// ----------------------------------------------------------------------
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QProgressBar prb;
Device device;
UserTest test;
QObject::connect(&test, SIGNAL(setValue(int)),
&device, SLOT(slotChangeValue(int))
);
QObject::connect(&device, SIGNAL(sendValue(int)),
&prb, SLOT(setValue(int))
);
prb.show();
test.start();
return app.exec();
}
#include "main.moc"