Opened 8 years ago

Closed 8 years ago

Last modified 7 years ago

#205 closed баг (fixed)

Гонки при использовании XMLConfig::ESLConferences

Reported by: alx Owned by: dimag
Priority: blocker Milestone: 2 очередь
Component: ПО MC04-Dispatcher. Пульт диспетчера/техника Keywords: потоки
Cc: san

Description

XMLConfig::ESLConferences используется в GUI потоке, например через функцию XMLConfig::getConferenceIndex(), и при этом модифицируется в Events::EventsTimerTick, то есть в другом потоке. Таким образом, возможна модификация одним потоком в процессе обращения из другого потока.

Change History (16)

comment:1 by dimag, 8 years ago

Я везде там где идёт обращение к объекту currentConfig ставлю
QMutex mutex;
QMutexLocker mutexlocker(&mutex);
Это должно предотвратить модификацию состояние объекта currentConfig из другого потока.

comment:2 by san, 8 years ago

Priority: majorcritical

comment:3 by dimag, 8 years ago

Keywords: потоки added
Resolution: fixed
Status: newclosed

r249.
Просмотрел исходный код, поставил мьютексы везде, где используются совместно используемые разными потоками ресурсы.

comment:4 by alx, 8 years ago

Resolution: fixed
Status: closedreopened

В репозитории нет r249.

comment:5 by dimag, 8 years ago

Resolution: fixed
Status: reopenedclosed

r248, извините.

comment:6 by alx, 8 years ago

Resolution: fixed
Status: closedreopened

Хм... В коммите r248 я не вижу добавления никаких мьютексов. Добавлен параметр в XMLConfig::ParseURI() и изменен фрагмент в StartupDlg.cpp, отвечающий, насколько я понял, за выбор логина по умолчанию при старте программы. Как это может устранить гонки при использовании XMLConfig::ESLConferences? По-моему, никак не может...

comment:7 by alx, 8 years ago

В r248 исправляет баг из тикета #201.

Version 0, edited 8 years ago by alx (next)

comment:8 by dimag, 8 years ago

r249
Я забыл закоммитеть изменения, просто я задумался о другом.

comment:9 by dimag, 8 years ago

Resolution: fixed
Status: reopenedclosed

comment:10 by alx, 8 years ago

Я так и не вижу в коде, что помешает потоку EventThread модифицировать XMLConfig::ESLConferences например по такой цепочке: Events::EventsTimerTick() -> Events::RefreshConferenceState(), в то время как выполняется обращение к XMLConfig::ESLConferences например по такой цепочке: MainAppFrameWindow3::StarEndConferenceButtonPressed() -> XMLConfig::getConferenceIndex(). По-моему гонки не устранены. Поправьте меня, если я неправ.

comment:11 by san, 8 years ago

Priority: criticalblocker
Resolution: fixed
Status: closedreopened

comment:12 by dimag, 8 years ago

Resolution: fixed
Status: reopenedclosed

Все вызовы RefreshConferenceState вызываются в во время действия мутекса, в коде аналогичным данному
QMutex mutex;
QMutexLocker mutexlocker(&mutex);
std::string sCallerChannel = EventParamValueMapCaller-Channel-Name;
RefreshConferenceState(sConference, sAffectedConferenceUserID, sAction);
Соотвественно, если пользователь нажмёт на кнопку вызвать/остановить конференцию во время выполнения функции StartEndConferenceButtonPressed, то функция выполниться до первого мьютекса, далее будет ждать разблокировки мьютекса в потоке EventThread.

В основном потоке и в остальных потоках в r249 и позднее, все обращения к разделяемым данным осуществляется через взятие мьютекса, то есть гонок быть не должно.

in reply to:  12 comment:13 by alx, 8 years ago

Replying to dimag:

Все вызовы RefreshConferenceState вызываются в во время действия мутекса,

Какого именно? Уточните, пожалуйста, его имя и место, где этот мьютекс определен в программе.

Соотвественно, если пользователь нажмёт на кнопку вызвать/остановить конференцию во время выполнения функции StartEndConferenceButtonPressed, то функция выполниться до первого мьютекса, далее будет ждать разблокировки мьютекса в потоке EventThread.

Извините, но здесь Вы пишете ерунду (поправьте если я ошибаюсь).

Во-первых, StartEndConferenceButtonPressed - это слот объекта mainWindow, к которому подключен сигнал pressed виджета кнопки. Код слота выполняется в основном (гуишном) потоке. Иными словами, StartEndConferenceButtonPressed() выполняется в том же потоке, который генерирует сигнал. Сигналы обрабатываются последовательно в цикле прямым вызовом кода слота, к которому сигнал подключен. Таким образом, описанная Вами ситуация принципиально невозможна - новый сигнал pressed не начнет обрабатываться до тех пор, пока не завершится StartEndConferenceButtonPressed(), вызванная в результате обработки предыдущего сигнала pressed. Здесь нет и не может быть никаких гонок, так как все выполняется в одном потоке.

Во-вторых, в приведенном примере кода:

{
  QMutex mutex;
  QMutexLocker mutexlocker(&mutex);
  ... делаем какую-то работу ...
}

никакой блокировки при захвате мьютекса быть не может. В приведенном коде Вы создаете объект мьютекса mutex с автоматической длительностью хранения. Исходным состоянием мьютекса является "свободен" (не захвачен). В следующей строке Вы захватываете mutex в конструкторе QMutexLocker. Так как на данный момент известно, что mutex свободен, при выполнении QMutexLocker mutexlocker(&mutex); никакой блокировки потока не будет. Далее по коду никаких других обращений к mutex нет. Таким образом, две первые строки этого примера, фактически, не имеют никакого эффекта.

Я же в comment:10 привел пример совсем другой ситуации - когда во время выполнения XMLConfig::getConferenceIndex(), вызванной из StarEndConferenceButtonPressed() выполнится Events::RefreshConferenceState(), вызванная из Events::EventsTimerTick() например в результате получения события add-mmber.

В основном потоке и в остальных потоках в r249 и позднее, все обращения к разделяемым данным осуществляется через взятие мьютекса,

Еще раз - уточните, пожалуйста, какого именно мьютекса. Возможно, Вам стоит освежить в памяти понятия "storage duration", "scope" и "linkage"...

то есть гонок быть не должно.

comment:14 by san, 8 years ago

Resolution: fixed
Status: closedreopened

comment:15 by dimag, 8 years ago

Resolution: fixed
Status: reopenedclosed

comment:16 by san, 7 years ago

Milestone: Текущее2 очередь

Milestone renamed

Note: See TracTickets for help on using tickets.