Есть класс для работы с девайсом, который помещается в QThread, в конструкторе класса объявлен таймер так:
timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(sl_timer()));
timer->start(0); //для наиболее частого опроса девайса 0 стоит.
sl_timer - это метод этого же класса, в котором идет опрос девайса. Этот метод и другие методы, которые вызываются из sl_timer и работают с глобальным QList защищены QMutex так:
QLockerMutex lock(&mutex);
В одном из 5-10 случаев происходят какие-то зависания внутри sl_timer, полагаю что мьютекс где-то зависает. Как бы найти в какой конкретно функции это происходит ?
Правильно ли я понимаю, что sl_timer из-за start(0) сможет вызваться второй раз еще когда первый вызов не отработал. То есть могут ли sl_timer тут начать работать параллельно и из-за локов мьютексами друг друга зависать ?
Код, который работает с листом должен быть прикрыт мьютексом. Мы это обсудили в твоей предыдущей теме. Ничего нового.
Также есть fun_basic, которая тоже с этим QList работает и может вызывать fun_i разные.
Кажется, я догадываюсь почему у тебя потоки зависают. Ты делаешь так?
voidfun_basic(){
QMutexLocker lock(mutex);
// Здесь работаешь с листом// Вызов другого метода, который работает тоже с листомfun_i();
}
voidfun_i(){
QMutexLocker lock(mutex); // <--- Опачки повторное взятие мьютекса// Здесь работаешь с листом
}
Если в подобном коде вызвать fun_basic, то будет вечная блокировка внутри fun_i.
Единственное, что заметил, это fun_basic вызывается по таймеру, у которого стояло start(0), могло это вызывать fun_basic следующую, пока там идет предыдущая еще ?
А как защиту поставить на fun_i и на fun_basic, у меня могут быть вызовы из других классов типа
worker->fun_i();
а может быть вызов fun_i внутри своего класса из fun_basic. То есть мне нужно определять как-то откуда был вызов, чтобы принимать решение блочить или нет мьютексом.
То есть если из fun_basic был вызов в fun_i, то я буду пропускать мьютекс. На fun_basic будет всегда мьютекс
Можно рекурсивный мьютекс вонзить, но это архитектурно криво выглядит.
Можно передавать в fun_i булевый параметр, который будет говорить нужно ли брать блокировку. Только тут нужно быть аккуратней с QMutexLocker. Если он будет внутри блока if, то после выхода из этого блока блокировка снимется. Ещё стоит отметить, что если этот метод публичный, то это тоже архитектурное говно. Не надо рассчитывать, что внешний код знает особенности внутреннего устройства класса.
Можно разделить метод fun_i на два: fun_i и fun_i_private. fun_i будет брать блокировку и вызывать fun_i_private, в котором находится вся логика, но уже без блокировки. Соответственно, если fun_basic уже взял блокировку, то он может напрямую вызвать fun_i_private, а остальные будут работать через fun_i.
Короче раздели интерфейс своего класса на thread-safe и не thread-safe. А то так путаница возникает. Самому же сложно за всем следить.
У меня setSensorValue вызывалась. Сигнал sig_TemperatureChanged связан со слотом clearAdcSpreading. Висло на clearAdcSpreading, но я полагал, что сигналы просто встанут в очередь и после выхода из цикла в setSensorValue мьютех освободится, и все эти сигналы исполнятся.
Но виснет сразу после первого.
Можете объяснить почему именно так работает ? Сигнал надо было как метод рассматривать ?
Сигналы встанут в очередь только при Qt::queuedConnection. Ты когда делаешь connect явно пропиши, что хочешь: Qt::queuedConnection или Qt::directConnection. В последнем случае это всё равно что прямой вызов метода.
А нужно ли тут все эти методы защищать мьютексом от крэша или на setTemp упасть не сможет из-за double типа ?
Методы setTemp, setState, setList вызываются другим тредом через сигналы