Название: Вызов сигнала в главном потоке Отправлено: Swa от Август 15, 2012, 14:37 Всем привет.
Есть поток, который осуществляет поиск подстроки в нескольких документах. Поток: Код: class SearchThread : public QThread { Результат поиска: Код: class SearchResult { Посредник: Код: class Mediator : public QObject { Мне нужно чтобы сигнал Mediator::Result выполнялся в главном потоке. К этому сигналу подключаются другие объекты и выполняют операции с гуи, что должно быть в главном потоке, но сигнал вызывается из потока поиска. Плюс к этому соединение потока поиска и посредника должно быть не через очередь, а прямое, иначе документ может быть удален после вызова сигнала, но до того, как дошла очередь до обработки этого сигнала, и указатель на документ станет невалидным. Как можно вызвать Mediator::Result в основном потоке или как-то по другому решить эту проблему? Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 15, 2012, 15:14 Ответ: Никак. Прямое соединение подразумевает вызов в том потоке, который вызывает.
Соединение через очередь вызывается в том потоке, в который послали. PS если у тебя такая архитектура, что "документ может быть закрыт", то почему бы не сделать "невозможно закрыть документ, пока не обработан сигнал"? Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 15, 2012, 15:31 А как узнать, что сигнал не обработан? Ведь нет прямого доступа к очереди событий.
Можно конечно блокировать возможность закрывать документы пока идет поиск но это как-то некрасиво. Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 15, 2012, 15:35 А что тебе мешает использовать очереди?
Мне немного трудно по коду понять что и как у тебя организовано. Мб опишешь свою идею в словах, а я подскажу как можно сделать/улучшить твою архитектуру? Название: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 15, 2012, 15:37 Можно так
Код Когда главная нитка видит Result с документом 0, она понимает что поиск завершен и документы можно удалять, и делать search.wait(). А QueuedConnection использовать придется т.к SearchThread выполняется асинхронно Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 15, 2012, 15:56 Bepec
Да ничего сложного: список по тексту документов. Юзер запускает поиск и продолжает дальше работать с документами, создавать, удалять и т.д. Вопрос в синхронизации. Igors Ну да, это получается единственный вариант. Название: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 15, 2012, 16:33 Да ничего сложного: список по тексту документов. Юзер запускает поиск и продолжает дальше работать с документами, создавать, удалять и т.д. Вопрос в синхронизации. Тогда надо лочить takeAt и делать поиск в слоте а не в run Название: Re: Вызов сигнала в главном потоке [РЕШЕНО] Отправлено: Swa от Август 15, 2012, 17:51 Вообщем, я тут немного подумал и сформулировал проблему немного точнее. В нулевом посте я как-то невнятно объяснил.
На самом деле в потоке стоят мютексы, просто я их опустил ради читабельности. Поток должен реагировать на удаление документа, но ниже описана ситуация, которую я не могу понять как решить. Код: class SearchThread : public QThread { Теперь такая ситуация: 1. SearchThread лочит мютекс и приступает к поиску по конкретному документу d. 2. В это время в основном потоке юзер нажимает на кнопку "Удалить документ d". Основной поток приходит в слот DeletingDocument и ждет мютекса. 3. Поток поиска отсылает сигналы с результатом поиска, заканчивает работать с документом d и открывает мютекс. Сигналы отправляются в очередь событий основного потока. 4. Основной поток пытается удалить документ d из списка, но там его нет. Он выходит из слота и освобождает память документа d. 5. После этого основной поток начинает обрабатывать данные сигналов Result, которые уже содержат невалидные указатели. Как обработать эту ситуацию? Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 15, 2012, 18:03 При нажатии кнопачки удалить документ проверять, идёт ли по нему поиск. Если да, то выдавать окно - аля "в данном документе производится поиск. При удалении документа поиск будет отменён" да/нет. Ну а если да, тогда в поток поиска отсылать сигнал - начать экстренную панику и прекращение потока поиска.
PS и овцы целы и волков постреляли. Название: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 15, 2012, 19:23 Так просто не выйдет, надо переделывать эту, как ее... "архитектуру" :)
Проще всего перенести поиск из run в слот. Главная нитка пуляет в этот слот документом для поиска. Удаляет тоже главная, так легче. SearchThread стоит, получмл документ, делает поиск, дальше стоит. Плюс у него стандартный флажок mAbort чтобы прекратить поиск (документ будет удален). Ну это жевали здесь многократно. Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 08:35 Igors
Я не совсем понимаю вашу мысль. Поиск производится сразу по всем документам. Если главная нитка будет перебирать все документы и посылать их в SearchThread, то она не сможет реагировать на действия юзера. Цитировать Ну это жевали здесь многократно. А можно ссылку на похожую тему?Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 16, 2012, 09:03 Поиск "сразу по всем" - плохая идея :)
К тому же у тебя идёт поиск последовательно, исходя из кода. У тебя итак сейчас идёт переборчик, правда из кода не очень понятно как туда они попадают. PS и уж точно, работа с <100 указателями в главной нитке ничем её не затормозит. Вообще :) Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 09:23 Сначала было так:
void Widget::SearchButtonPressed() { thread->list = this->list; thread.start(); } Но Igors советует отдавать в поток один документ: void Widget::SearchButtonPressed() { foreach(Document* d, list) { thread->document = d; thread.start(); thread.wait(); } <- главный поток ждет конца поиска } А почему поиск по всем - плохая идея? Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 16, 2012, 09:39 Напиши, хотя бы псевдокодом, как ты будешь искать одновременно (не последовательно) по всем документам?
PS это возможно только когда на каждый документ будет 1 поток :D А >8 потоков в программе - плохо :D Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 09:55 Наверное мы друг друга не поняли :). Поиск, естественно, идёт последовательно. Код перебора - в предыдущем ответе.
Название: Re: Вызов сигнала в главном потоке Отправлено: Bepec от Август 16, 2012, 09:58 Проще выражаясь - у тебя всё уже готово, надо просто перенести часть, ответственную за подсовывание документов вынести в основной поток.
PS ага ) Название: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 16, 2012, 12:25 Я не совсем понимаю вашу мысль. Поиск производится сразу по всем документам. Если главная нитка будет перебирать все документы и посылать их в SearchThread, то она не сможет реагировать на действия юзера. Главная нитка запускает SearchThread и делает напр emit SearchDoc(doc[ i ]) столько раз сколько есть документов, после этого она свободна. Посланные документы (указатели) оказались в очереди событий (EventLoop) SearchThread, т.е. документы для поиска ему приходят один за однимТакже главная нитка может послать NULL документ. Увидев его SearchThread понимает - больше доков не будет и выходит из run послав сигнал "поиск завершен" Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 14:53 Вообщем я сделал так:
Поток поиска ищет в одном конкретном документе, не знает ничего о списке. Код: Mediator::Mediator() { Не слишком коряво? Название: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 16, 2012, 15:32 Ну "достаточно коряво" :) Перезапуск нитки на каждый документ - удовольствие дорогое, да и непонятно кто будет все время толкать processSearchQueue
Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 15:49 processSearchQueue первый раз запускается из метода StartSearch, а потом он запускается по сигналу finished() треда.
Больше в голову не приходит как сделать. Название: Re: Вызов сигнала в главном потоке Отправлено: Swa от Август 16, 2012, 16:02 Главная нитка запускает SearchThread и делает напр emit SearchDoc(doc[ i ]) столько раз сколько есть документов, после этого она свободна. Посланные документы (указатели) оказались в очереди событий (EventLoop) SearchThread, т.е. документы для поиска ему приходят один за одним В этом случае будет использовано прямое соединение, а не очередьНазвание: Re: Вызов сигнала в главном потоке Отправлено: Igors от Август 17, 2012, 11:44 В этом случае будет использовано прямое соединение, а не очередь Так надо сделать moveToThread. Удаление можно так:- при завершении поиска в документе SearchThread испускает сигнал "поиск закончен". Главная нитка, поймав этот сигнал, смотрит - если документ помечен к удалению - удалить его. Также SearchThread может закруглиться с поиском увидев маркер удаления. В общем с байтом флажков у документа получается покороче, но и Ваш вариант рабочий. |