Russian Qt Forum
Ноябрь 23, 2024, 02:46 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Нужно ли блокировать доступ к переменной в главном потоке (QMutex)?  (Прочитано 7110 раз)
thechicho
Гость
« : Февраль 05, 2014, 14:27 »

Допустим в главном потоке есть переменная QStringList tmp;
Через определенный промежуток времени в этом потоке вызывается слот (slot1), в котором эта переменная перезаписывается (tmp = tmpList;).
Так же работает n-ое количество потоков, созданных в главном потоке.
Эти потоки многократно вызывают слот (slot2) в главном потоке в произвольный момент времени, в котором рассматриваемая переменная модифицируется (tmp.takeFirst()Подмигивающий;
Вопрос - может ли в один момент времени произойти доступ к переменной из разных слотов? То есть слоты (и обычные функции?) обрабатываются в главном потоке всегда последовательно или могут обрабатываться одновременно, т.к. вызываются из разных мест в произвольное время.
Нужен мьютекс или нет:
void MainThread::slot1(QStringList tmpList)
{
    mutex.lock();
    tmp = tmpList;
    mutex.unlock();
}
void MainThread::slot2()
{
    mutex.lock();
    QString str = tmp.takeFirst();
    mutex.unlock();
}
кроме ответа на вопрос буду благодарен за ликбез или ссылку на статью по теме. не вообще про многопоточность, а именно по этому контексту.
Записан
Serr500
Гость
« Ответ #1 : Февраль 05, 2014, 19:40 »

слоты (и обычные функции?) обрабатываются в главном потоке всегда последовательно или могут обрабатываться одновременно, т.к. вызываются из разных мест в произвольное время.
В главном потоке ничего не может обрабатываться одновременно. Одновременно могут идти обработки только в разных потоках. Пока в рамках цикла сообщений выполняется одна функция, другая не может быть выполнена. Иными словами, если запустился на обработку слот, другой слот не начнёт обработку до тех пор, пока первый не закончит свою работу. Однако, если внутри слота выполнить QCoreApplication::processEvents, то в этот момент вполне может быть запущен на выполнение другой слот.

Через определенный промежуток времени в этом потоке вызывается слот (slot1), в котором эта переменная перезаписывается (tmp = tmpList;).
Так же работает n-ое количество потоков, созданных в главном потоке.
Эти потоки многократно вызывают слот (slot2) в главном потоке в произвольный момент времени, в котором рассматриваемая переменная модифицируется (tmp.takeFirst()Подмигивающий;
Вопрос - может ли в один момент времени произойти доступ к переменной из разных слотов?
Вопрос поставлен немного некорректно, поскольку ответ на него зависит от типа соединений сигналов и слотов. Если рассматривать все варианты, то да, может.

Дело здесь в том, как именно вызываются слоты. Если слот вызывается как обычная функция
Код:
obj1->slot1();
то этот слот будет выполнен не в главном потоке, а в том, из которого этот оператор был вызван. В этом случае мьютекс необходим.
Если слот вызывается через сигнал
Код:
connect(this, SIGNAL(signal1()), obj1, SLOT(slot1()));
// . . .
emit signal1()
то всё зависит от типа соединения. Если соединение такое, как здесь, то используется автоопределение и в случае, когда объекты принадлежат разным потокам, будет использовано Qt::QueuedConnection. В этом случае вызов слота встанет в очередь и будет выполнен циклом обработки сообщений главного потока в его контексте когда дойдёт очередь. Одновременного обращения к переменной в данном случае не будет. Чтобы автоопределение работало гарантированно точно, всем объектам надо сделать moveToThread. Если же будет использовано Qt::DirectConnection, то слот будет вызван почти как обычная функция в контексте вызывающего потока и возможно одновременное обращение к переменной.

P.S. Вместо
Код:
mutex.lock();
// . . .
mutex.unlock();
рекомендуется использовать
Код:
{
    QMutexLocker(&mutex);
    // . . .
}
Во второй конструкции мьютекс будет гарантированно разблокирован даже если код вызвал ошибку внутри блока. В первом случае возможна "мёртвая блокировка".
Записан
thechicho
Гость
« Ответ #2 : Февраль 06, 2014, 19:09 »

а если в потоке (worker) выполняется какая-то длительная по времени функция и во время ее выполнения из другого (главного) потока приходит сигнал, соединенный (без указания типа соединения) с слотом в потоке (worker). то этот слот выполнится до завершения выполнения функции (говорю по опыту).
но, когда будет выполняться этот слот, функция приостановит свою работу или они выполнятся одновременно?
то есть: в функции и слоте есть одна глобальная переменная. нужно ли использовать мьютекс в слоте при доступе к этой переменной? ведь когда в слоте происходит доступ к переменной, в фукнции тоже может в этот же момент времени произойти доступ к этой переменной?

то есть если я использую мьютекс, то при одновременном выполнении функции и слота, функция должна приостановить свою работу, пока мьютекс в слоте не разблокируется. тем самым переменная будет защищена от одновременного доступа из функции и слота.
или как это все работает? Непонимающий
« Последнее редактирование: Февраль 06, 2014, 19:13 от thechicho » Записан
Serr500
Гость
« Ответ #3 : Февраль 06, 2014, 21:50 »

а если в потоке (worker) выполняется какая-то длительная по времени функция и во время ее выполнения из другого (главного) потока приходит сигнал, соединенный (без указания типа соединения) с слотом в потоке (worker). то этот слот выполнится до завершения выполнения функции (говорю по опыту).
Посмотрите на currentThread(). Наверняка слот выполнился в главном потоке. Т.е. вызов был типа Qt::DirectConnection.

но, когда будет выполняться этот слот, функция приостановит свою работу или они выполнятся одновременно?
В рамках одного потока одновременное выполнение невозможно. Функция не может приостановить работу, только если она не была специально так спроектирована (ну, или случайно...  Подмигивающий ). Если слот вызван из другого потока, то возможно только две ситуации:
1) Вызов слота встал в очередь потока worker. Слот будет выполнен при возврате к циклу сообщений, т.е. после завершения функции.
2) Слот выполнился внутри главного потока. В этом случае выполнение одновременное.

то есть если я использую мьютекс, то при одновременном выполнении функции и слота, функция должна приостановить свою работу, пока мьютекс в слоте не разблокируется. тем самым переменная будет защищена от одновременного доступа из функции и слота.
Да. Но только если функция и слот будут работать в разных потоках. Похоже, в Вашем случае это именно так. Если поток один -получите "мёртвую блокировку".

По-моему, Вас вводит в заблуждение слово "слот". Забудьте про него. Слот - это такая же функция. Просто для неё можно применить другие методы вызова. Но этот метод - всего лишь хитрая обёртка, которая в итоге вызовет эту функцию. И как любая функция она может выполниться внутри любого потока.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Февраль 07, 2014, 11:15 »

Слот - это такая же функция. Просто для неё можно применить другие методы вызова. Но этот метод - всего лишь хитрая обёртка, которая в итоге вызовет эту функцию. И как любая функция она может выполниться внутри любого потока.
По ходу дела вопрос - а само Qt защищает вызов слота мутексом или нет?
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #5 : Февраль 07, 2014, 12:10 »

По ходу дела вопрос - а само Qt защищает вызов слота мутексом или нет?
Если используется механизм Qt (invoke, или сигнал), второй вызов этого же слота отработает после текущего, если вызван просто как метод, то тут уж сам себе злобный буратино.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Февраль 07, 2014, 12:27 »

Если используется механизм Qt (invoke, или сигнал), второй вызов этого же слота отработает после текущего, если вызван просто как метод, то тут уж сам себе злобный буратино.
Ну с Буратино ясно, но-все-таки четкого ответа не прозвучало - защищены или как? Может ли слот выполняться одновременно (разумеется разными нитками)?
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #7 : Февраль 07, 2014, 12:37 »

Если объекты принадлежат разным тредам, то да, почему бы и нет.
Один объект не может принадлежать нескольким тредам одновременно.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Февраль 07, 2014, 12:43 »

Если объекты принадлежат разным тредам, то да, почему бы и нет.
Наверное Вы больше склонны к гуманитарным вещам (живопись, музыка) чем к техническим где есть четкое Да/Нет  Улыбающийся
Записан
Johnik
Крякер
****
Offline Offline

Сообщений: 339


Просмотр профиля
« Ответ #9 : Февраль 07, 2014, 12:56 »

Наверное Вы больше склонны к гуманитарным вещам (живопись, музыка) чем к техническим где есть четкое Да/Нет  Улыбающийся
Вы обо мне ничего не знаете, чтоб делать такие выводы.

Я же вижу, что очень многие недопонимают работу с многопоточными алгоритмами.
Еще раз:
1. Есть объект (класс которого унаследован от QObject). Объект принадлежит одному потоку. Как запустить слот 2 раза механизмом Qt, чтоб "каждый запуск" выполнялся одновременно. Ответ: НИКАК.

2. Есть 2 объекта, принадлежат одному потоку. Даже тут может одновременно выполняться только один слот в контексте одного объекта единомоментно.

3. Есть 2 объекта, и 2 потока, соответственно может выполняться слот одновременно в каждом потоке, каждый в контексте своего объекта.

PS. В Qt довольно грамотно сделана работа с потоками, по сравнению с другим инструментами (Java, .net, а с ними я тоже работал) /это мое личное мнение/.
Записан
Serr500
Гость
« Ответ #10 : Февраль 07, 2014, 18:19 »

По ходу дела вопрос - а само Qt защищает вызов слота мутексом или нет?
Не могу ответить на этот вопрос. Какие-то объекты синхронизации там есть, но глубоко в "потроха" сигнал-слотового механизма я не залезал.

Я же вижу, что очень многие недопонимают работу с многопоточными алгоритмами.
Еще раз:
1. Есть объект (класс которого унаследован от QObject). Объект принадлежит одному потоку. Как запустить слот 2 раза механизмом Qt, чтоб "каждый запуск" выполнялся одновременно. Ответ: НИКАК.
Вы тоже недопонимаете работу с многопоточными алгоритмами. Можно. А как именно - это Вам простенькая задачка.  Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Февраль 07, 2014, 19:47 »

Не могу ответить на этот вопрос. Какие-то объекты синхронизации там есть, но глубоко в "потроха" сигнал-слотового механизма я не залезал.
Аналогично. Я видел мутекс вроде используемый даже при DirectConnection но что он делает - не знаю

чтоб "каждый запуск" выполнялся одновременно. Ответ: НИКАК.
Не понимаю что имеется ввиду (чтоб "каждый запуск" выполнялся одновременно)  Непонимающий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.09 секунд. Запросов: 23.